add check on reload
This commit is contained in:
parent
ec4850cbb8
commit
470cae3b13
|
|
@ -1,5 +1,4 @@
|
||||||
import TextArea from 'antd/es/input/TextArea';
|
import TextArea from 'antd/es/input/TextArea';
|
||||||
import { useFormikContext } from 'formik';
|
|
||||||
import React, { Suspense, useEffect, useState } from 'react';
|
import React, { Suspense, useEffect, useState } from 'react';
|
||||||
import { parseTextAndLatex } from '../../utils/parseTextAndLatex';
|
import { parseTextAndLatex } from '../../utils/parseTextAndLatex';
|
||||||
import LatexPreview from '../CustomFields/MathComponent';
|
import LatexPreview from '../CustomFields/MathComponent';
|
||||||
|
|
@ -49,15 +48,24 @@ const LaTeXInputMemo: React.FC<any> = React.memo(({ field ,form, label, ...prop
|
||||||
setCurrentValue(e.target.value)
|
setCurrentValue(e.target.value)
|
||||||
};
|
};
|
||||||
const onBlur = ()=>{
|
const onBlur = ()=>{
|
||||||
|
if (curCentValue !== value) {
|
||||||
setFieldValue(name, curCentValue);
|
setFieldValue(name, curCentValue);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(Success){
|
if(Success){
|
||||||
setCurrentValue(null)
|
setCurrentValue(null)
|
||||||
}
|
}
|
||||||
}, [Success])
|
}, [Success])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if(value){
|
||||||
|
setCurrentValue(value)
|
||||||
|
}
|
||||||
|
}, [value])
|
||||||
|
|
||||||
|
|
||||||
const isError = !!touched?.[name] && !!errors?.[name];
|
const isError = !!touched?.[name] && !!errors?.[name];
|
||||||
const errorMessage = isError ? errors?.[name] as string ?? "" : "" ;
|
const errorMessage = isError ? errors?.[name] as string ?? "" : "" ;
|
||||||
return (
|
return (
|
||||||
|
|
@ -93,7 +101,7 @@ const LaTeXInputMemo: React.FC<any> = React.memo(({ field ,form, label, ...prop
|
||||||
{Preview?.map((item: any, index: number) => {
|
{Preview?.map((item: any, index: number) => {
|
||||||
if (item?.isLatex) {
|
if (item?.isLatex) {
|
||||||
return (
|
return (
|
||||||
<div key={index} onClick={() => handleEditModal(item)} className='LatexPreview'>
|
<div dir='ltr' key={index} onClick={() => handleEditModal(item)} className='LatexPreview'>
|
||||||
<LatexPreview Latex={item?.text} />
|
<LatexPreview Latex={item?.text} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
@ -104,9 +112,10 @@ const LaTeXInputMemo: React.FC<any> = React.memo(({ field ,form, label, ...prop
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<Suspense fallback={<SpinContainer />}>
|
||||||
<AddLazyModal name={name} Latex={Latex} isModalOpen={isModalOpen} setIsModalOpen={setIsModalOpen} setLatex={setLatex} setCurrentValue={setCurrentValue} />
|
<AddLazyModal name={name} Latex={Latex} isModalOpen={isModalOpen} setIsModalOpen={setIsModalOpen} setLatex={setLatex} setCurrentValue={setCurrentValue} />
|
||||||
<EditLazyModal name={name} Latex={Latex} isModalOpen={isEditModalOpen} setIsModalOpen={setIsEditModalOpen} setLatex={setLatex} />
|
<EditLazyModal name={name} Latex={Latex} isModalOpen={isEditModalOpen} setIsModalOpen={setIsEditModalOpen} setLatex={setLatex} />
|
||||||
<Suspense fallback={<SpinContainer />}>
|
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
42
src/Hooks/useUnsavedChangesWarning.tsx
Normal file
42
src/Hooks/useUnsavedChangesWarning.tsx
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
const useUnsavedChangesWarning = (unsavedChanges: boolean) => {
|
||||||
|
const [t] = useTranslation();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleBeforeUnload = (event: BeforeUnloadEvent) => {
|
||||||
|
if (unsavedChanges) {
|
||||||
|
// Prevent default action and stop the event
|
||||||
|
event.preventDefault();
|
||||||
|
// Optionally set returnValue to an empty string
|
||||||
|
event.returnValue = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNavigation = (event: MouseEvent) => {
|
||||||
|
if (unsavedChanges) {
|
||||||
|
console.log(t("Access denied: You have unsaved changes!"));
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('beforeunload', handleBeforeUnload);
|
||||||
|
|
||||||
|
// Intercept link clicks (example for <a> elements)
|
||||||
|
document.querySelectorAll('a').forEach(link => {
|
||||||
|
link.addEventListener('click', handleNavigation);
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('beforeunload', handleBeforeUnload);
|
||||||
|
|
||||||
|
// Clean up event listeners
|
||||||
|
document.querySelectorAll('a').forEach(link => {
|
||||||
|
link.removeEventListener('click', handleNavigation);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}, [unsavedChanges, t]);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useUnsavedChangesWarning;
|
||||||
|
|
@ -36,7 +36,6 @@ const DynamicTags = () => {
|
||||||
if (currentElement) {
|
if (currentElement) {
|
||||||
currentElement.focus(); // Set focus on the element
|
currentElement.focus(); // Set focus on the element
|
||||||
}
|
}
|
||||||
console.log(currentElement,"currentElement");
|
|
||||||
}, [lastElementIndex])
|
}, [lastElementIndex])
|
||||||
|
|
||||||
// console.log(formik?.values);
|
// console.log(formik?.values);
|
||||||
|
|
|
||||||
|
|
@ -167,7 +167,6 @@ const DrapableTable: React.FC = () => {
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
const columns = useColumns();
|
const columns = useColumns();
|
||||||
const sortedDataSource = dataSource.sort((a, b) => a.order - b.order);
|
const sortedDataSource = dataSource.sort((a, b) => a.order - b.order);
|
||||||
console.log(sortedDataSource, "sortedDataSource");
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DndContext modifiers={[restrictToVerticalAxis]} onDragEnd={onDragEnd}>
|
<DndContext modifiers={[restrictToVerticalAxis]} onDragEnd={onDragEnd}>
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,23 @@
|
||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { Spin } from "antd";
|
|
||||||
import {
|
import {
|
||||||
getInitialValues,
|
|
||||||
getValidationSchema,
|
|
||||||
getInitialValuesBase,
|
|
||||||
getValidationSchemaBase,
|
|
||||||
processTags,
|
processTags,
|
||||||
} from "./formUtil";
|
} from "./formUtil";
|
||||||
import { useAddQuestion, useAddQuestionAsync } from "../../../api/Question";
|
import { useAddQuestion, useAddQuestionAsync } from "../../../api/Question";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useParams } from "react-router-dom";
|
||||||
import { useLocation, useNavigate, useParams } from "react-router-dom";
|
|
||||||
import { ParamsEnum } from "../../../enums/params";
|
import { ParamsEnum } from "../../../enums/params";
|
||||||
import { useObjectToEdit } from "../../../zustand/ObjectToEditState";
|
import { useObjectToEdit } from "../../../zustand/ObjectToEditState";
|
||||||
|
|
||||||
import Header from "../../../Components/exercise/Header";
|
|
||||||
import { Question } from "../../../types/Item";
|
import { Question } from "../../../types/Item";
|
||||||
import BaseForm from "./Model/Malty/Form";
|
import BaseFormContainer from "./Model/AddForm/BaseForm";
|
||||||
import ModelForm from "./Model/ModelForm";
|
import FormContainer from "./Model/AddForm/Form";
|
||||||
import { toast } from "react-toastify";
|
import { handleValidateBaseQuestion, handleValidateSingleQuestion } from "./Model/AddForm/ValidationFn";
|
||||||
import { Form, Formik } from "formik";
|
import useUnsavedChangesWarning from "../../../Hooks/useUnsavedChangesWarning";
|
||||||
import { MdOutlineArrowForwardIos } from "react-icons/md";
|
import { useFormikContext } from "formik";
|
||||||
|
|
||||||
const AddPage: React.FC = () => {
|
const AddPage: React.FC = () => {
|
||||||
const location = useLocation();
|
|
||||||
|
|
||||||
const { mutateAsync, isLoading: LoadingAsync } = useAddQuestionAsync();
|
const { mutateAsync, isLoading: LoadingAsync } = useAddQuestionAsync();
|
||||||
const { mutate, isLoading, isSuccess } = useAddQuestion();
|
const { mutate, isLoading, isSuccess } = useAddQuestion();
|
||||||
const { isBseQuestion, setTagsSearch, setSuccess } =
|
const { isBseQuestion, setTagsSearch, setSuccess } = useObjectToEdit();
|
||||||
useObjectToEdit();
|
|
||||||
|
|
||||||
const [t] = useTranslation();
|
|
||||||
const { subject_id, lesson_id } = useParams<ParamsEnum>();
|
const { subject_id, lesson_id } = useParams<ParamsEnum>();
|
||||||
|
|
||||||
const handleFormSubmit = (values: any) => {
|
const handleFormSubmit = (values: any) => {
|
||||||
|
|
@ -100,215 +88,26 @@ const AddPage: React.FC = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleValidateSingleQuestion = (values:any,isValid:boolean,handleSubmit:any)=>{
|
|
||||||
const haveMoreThanOneAnswer = values?.answers?.length > 1;
|
|
||||||
const haveOneAnswerRight = haveMoreThanOneAnswer && values?.answers?.some((item:any)=> item?.isCorrect === 1 || item.isCorrect === true )
|
|
||||||
const haveImageOrContent = haveOneAnswerRight && values?.answers?.some((item:any)=> !(item?.content) && !(item.content_image) )
|
|
||||||
const content = values.content ;
|
|
||||||
const content_image = values.content_image ;
|
|
||||||
const haveContentOrContentImage = !!content || !!content_image ;
|
|
||||||
console.log(haveImageOrContent,"haveImageOrContent");
|
|
||||||
if(!haveContentOrContentImage){
|
|
||||||
toast.error(`${t("validation.one_of_image_and_content_should_be_enter_in_question")}`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!haveMoreThanOneAnswer){
|
|
||||||
toast.error(t("validation.it_should_have_more_than_one_answers")) ;
|
|
||||||
return false ;
|
|
||||||
}
|
|
||||||
if(!haveOneAnswerRight){
|
|
||||||
toast.error(t("validation.it_should_have_more_than_one_correct_answers")) ;
|
|
||||||
return false ;
|
|
||||||
}
|
|
||||||
if(haveImageOrContent){
|
|
||||||
toast.error(t("validation.one_of_image_and_content_should_be_enter_in_answer"))
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(1);
|
|
||||||
|
|
||||||
if(isValid){
|
|
||||||
handleSubmit(values)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
const handleValidateBaseQuestion = (values: any,isValid:boolean,handleSubmit:any) => {
|
|
||||||
const content = values.content ;
|
|
||||||
const content_image = values.content_image ;
|
|
||||||
const haveContentOrContentImage = !!content || !!content_image ;
|
|
||||||
console.log(2);
|
|
||||||
|
|
||||||
if(!haveContentOrContentImage){
|
|
||||||
toast.error(`${t("validation.one_of_image_and_content_should_be_enter_in_question")}`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
console.log(1);
|
|
||||||
|
|
||||||
const isValidate = values?.Questions?.every((Question: any, QuestionsIndex: number) => {
|
|
||||||
|
|
||||||
|
|
||||||
const content = Question.content ;
|
|
||||||
const content_image = Question.content_image ;
|
|
||||||
const haveContentOrContentImage = !!content || !!content_image ;
|
|
||||||
if(!haveContentOrContentImage){
|
|
||||||
toast.error(`${t("validation.one_of_image_and_content_should_be_enter_in_question")}`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//// answers
|
|
||||||
const answers = Question?.answers;
|
|
||||||
const haveAnswers = answers?.length > 0;
|
|
||||||
const haveMoreThanOneAnswer = haveAnswers && answers?.length > 1;
|
|
||||||
const haveOneAnswerRight = haveMoreThanOneAnswer && answers?.some((item: any) => item?.isCorrect === 1 || item.isCorrect === true);
|
|
||||||
const haveImageOrContent = haveOneAnswerRight && answers?.some((item:any)=> !(item?.content) && !(item.content_image) )
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (!haveAnswers) {
|
|
||||||
toast.error(t("validation.it_should_have_more_than_one_answers"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!haveMoreThanOneAnswer) {
|
|
||||||
toast.error(t("validation.it_should_have_more_than_one_answers"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!haveOneAnswerRight) {
|
|
||||||
toast.error(t("validation.it_should_have_more_than_one_correct_answers"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(haveImageOrContent){
|
|
||||||
toast.error(t("validation.one_of_image_and_content_should_be_enter_in_answer"))
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(1);
|
|
||||||
|
|
||||||
if(isValid && isValidate){
|
|
||||||
console.log(2);
|
|
||||||
handleSubmit(values)
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
const handleNavigateToPage = () => {
|
|
||||||
const cleanedUrl = location.pathname?.replace("/Question/add", "");
|
|
||||||
navigate(cleanedUrl);
|
|
||||||
};
|
|
||||||
const handleCancel = () => {
|
|
||||||
navigate(-1);
|
|
||||||
};
|
|
||||||
const Loading = LoadingAsync || isLoading;
|
const Loading = LoadingAsync || isLoading;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isSuccess) {
|
if (isSuccess) {
|
||||||
setSuccess(true);
|
setSuccess(true);
|
||||||
|
|
||||||
}
|
}
|
||||||
}, [isSuccess]);
|
}, [isSuccess]);
|
||||||
|
|
||||||
if (isBseQuestion) {
|
if (isBseQuestion) {
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<div className="QuestionPractical">
|
<BaseFormContainer Loading={Loading} handleFormSubmit={handleFormSubmit} handleValidateBaseQuestion={handleValidateBaseQuestion} />
|
||||||
<header>
|
|
||||||
<MdOutlineArrowForwardIos onClick={handleNavigateToPage} /> {t("header.add_new_question")}
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div className="exercise_add">
|
|
||||||
<Formik
|
|
||||||
onSubmit={handleFormSubmit}
|
|
||||||
initialValues={getInitialValuesBase({} as any)}
|
|
||||||
validationSchema={getValidationSchemaBase}
|
|
||||||
enableReinitialize
|
|
||||||
|
|
||||||
>
|
|
||||||
{({ values,isValid,handleSubmit }) => (
|
|
||||||
|
|
||||||
<Form className="w-100">
|
|
||||||
<main className="w-100 exercise_add_main">
|
|
||||||
<Header />
|
|
||||||
<BaseForm />
|
|
||||||
|
|
||||||
<div className="exercise_add_buttons">
|
|
||||||
<div onClick={handleCancel}>{t("practical.back")}</div>
|
|
||||||
<button disabled={Loading} className="relative" type="button"
|
|
||||||
onClick={()=>{handleValidateBaseQuestion(values,isValid,handleSubmit) }}
|
|
||||||
onSubmit={()=>{handleValidateBaseQuestion(values,isValid,handleSubmit) }}
|
|
||||||
>
|
|
||||||
{t("practical.add")}
|
|
||||||
|
|
||||||
{Loading && (
|
|
||||||
<span className="Spinier_Div">
|
|
||||||
<Spin />
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
</Form>
|
|
||||||
)}
|
|
||||||
</Formik>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<div className="QuestionPractical">
|
<FormContainer Loading={Loading} handleFormSubmit={handleFormSubmit} handleValidateSingleQuestion={handleValidateSingleQuestion} />
|
||||||
<header>
|
|
||||||
<MdOutlineArrowForwardIos onClick={handleNavigateToPage} /> {t("header.add_new_question")}
|
|
||||||
</header>
|
|
||||||
<div className="exercise_add">
|
|
||||||
<Formik
|
|
||||||
enableReinitialize={true}
|
|
||||||
initialValues={getInitialValues({} as any)}
|
|
||||||
validationSchema={getValidationSchema}
|
|
||||||
validateOnMount={true}
|
|
||||||
onSubmit={(values) => {
|
|
||||||
handleFormSubmit(values);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{({ values,isValid ,handleSubmit}) => (
|
|
||||||
<Form className="w-100">
|
|
||||||
<main className="w-100 exercise_add_main">
|
|
||||||
<Header />
|
|
||||||
<ModelForm />
|
|
||||||
|
|
||||||
<div className="exercise_add_buttons">
|
|
||||||
<div onClick={handleCancel}>{t("practical.back")}</div>
|
|
||||||
<div
|
|
||||||
className="relative"
|
|
||||||
onClick={()=>{ Loading ? ()=>{} : handleValidateSingleQuestion(values,isValid,handleSubmit) }}
|
|
||||||
>
|
|
||||||
{t("practical.add")}
|
|
||||||
|
|
||||||
{Loading && (
|
|
||||||
<span className="Spinier_Div">
|
|
||||||
<Spin />
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
</Form>
|
|
||||||
)}
|
|
||||||
</Formik>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,5 @@
|
||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { Checkbox, Modal, Popover, Spin } from "antd";
|
|
||||||
import {
|
import {
|
||||||
getInitialValues,
|
|
||||||
getValidationSchema,
|
|
||||||
getInitialValuesBase,
|
|
||||||
getValidationSchemaBase,
|
|
||||||
processTags,
|
processTags,
|
||||||
} from "./formUtil";
|
} from "./formUtil";
|
||||||
import {
|
import {
|
||||||
|
|
@ -19,16 +14,11 @@ import { ParamsEnum } from "../../../enums/params";
|
||||||
import { useObjectToEdit } from "../../../zustand/ObjectToEditState";
|
import { useObjectToEdit } from "../../../zustand/ObjectToEditState";
|
||||||
import { removeStringKeys } from "../../../utils/removeStringKeys";
|
import { removeStringKeys } from "../../../utils/removeStringKeys";
|
||||||
import SpinContainer from "../../../Components/Layout/SpinContainer";
|
import SpinContainer from "../../../Components/Layout/SpinContainer";
|
||||||
import ModelForm from "./Model/ModelForm";
|
|
||||||
import BaseForm from "./Model/Malty/Form";
|
|
||||||
import { Question } from "../../../types/Item";
|
import { Question } from "../../../types/Item";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import { deletePathSegments } from "../../../utils/deletePathSegments";
|
import { deletePathSegments } from "../../../utils/deletePathSegments";
|
||||||
import { Form, Formik } from "formik";
|
import BaseFormContainer from "./Model/EditForm/BaseFormContainer";
|
||||||
import { MdOutlineArrowForwardIos } from "react-icons/md";
|
import FormContainer from "./Model/EditForm/FormContainer";
|
||||||
import { SettingFilled } from "@ant-design/icons";
|
|
||||||
import { CheckboxProps } from "antd/lib";
|
|
||||||
import { LocalStorageEnum } from "../../../enums/LocalStorageEnum";
|
|
||||||
|
|
||||||
const EditPage: React.FC = () => {
|
const EditPage: React.FC = () => {
|
||||||
const { subject_id, lesson_id, question_id } = useParams<ParamsEnum>();
|
const { subject_id, lesson_id, question_id } = useParams<ParamsEnum>();
|
||||||
|
|
@ -79,7 +69,7 @@ const EditPage: React.FC = () => {
|
||||||
console.log(DeletedQuestions, "DeletedQuestions");
|
console.log(DeletedQuestions, "DeletedQuestions");
|
||||||
console.log(UpdateBseQuestion);
|
console.log(UpdateBseQuestion);
|
||||||
|
|
||||||
// mutate(UpdateBseQuestion);
|
mutate(UpdateBseQuestion);
|
||||||
|
|
||||||
DeletedQuestions?.map((item: any) => {
|
DeletedQuestions?.map((item: any) => {
|
||||||
DeleteQuestion({ id: item?.id });
|
DeleteQuestion({ id: item?.id });
|
||||||
|
|
@ -187,9 +177,6 @@ const EditPage: React.FC = () => {
|
||||||
|
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const handleCancel = () => {
|
|
||||||
navigate(-1);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleValidateSingleQuestion = (values: any, isValid: boolean, handleSubmit: any) => {
|
const handleValidateSingleQuestion = (values: any, isValid: boolean, handleSubmit: any) => {
|
||||||
const haveMoreThanOneAnswer = values?.answers?.length > 1;
|
const haveMoreThanOneAnswer = values?.answers?.length > 1;
|
||||||
|
|
@ -288,11 +275,6 @@ if(isValid && isValidate){
|
||||||
handleSubmit(values)
|
handleSubmit(values)
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleNavigateToPage = () => {
|
|
||||||
const cleanedUrl = location.pathname.replace(/\/Question\/\d+$/, "");
|
|
||||||
navigate(cleanedUrl);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -302,31 +284,6 @@ const handleNavigateToPage = () => {
|
||||||
}
|
}
|
||||||
}, [isSuccess]);
|
}, [isSuccess]);
|
||||||
|
|
||||||
const onChangeHint: CheckboxProps['onChange'] = (e) => {
|
|
||||||
setShowHint(e.target.checked);
|
|
||||||
localStorage?.setItem(LocalStorageEnum.HINT_INPUT,e.target.checked ? "true" : "false" )
|
|
||||||
};
|
|
||||||
|
|
||||||
const onChangeLatexOption: CheckboxProps['onChange'] = (e) => {
|
|
||||||
setShowLatexOption(e.target.checked);
|
|
||||||
localStorage?.setItem(LocalStorageEnum.LATEX_OPTION_INPUT,e.target.checked ? "true" : "false" )
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const contentSetting = (
|
|
||||||
<div>
|
|
||||||
|
|
||||||
<Checkbox checked={ShowHint} onChange={onChangeHint}>
|
|
||||||
{ t("header.show_hint")}
|
|
||||||
</Checkbox>
|
|
||||||
|
|
||||||
<Checkbox checked={ShowLatexOption} onChange={onChangeLatexOption}>
|
|
||||||
{ t("header.show_MMl")}
|
|
||||||
</Checkbox>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -337,119 +294,13 @@ const handleNavigateToPage = () => {
|
||||||
}
|
}
|
||||||
if (objectToEdit?.isBase) {
|
if (objectToEdit?.isBase) {
|
||||||
return (
|
return (
|
||||||
|
<BaseFormContainer t={t} Loading={Loading} handleSubmit={handleSubmit} handleValidateBaseQuestion={handleValidateBaseQuestion} objectToEdit={objectToEdit} />
|
||||||
|
|
||||||
<div className="QuestionPractical">
|
|
||||||
<header>
|
|
||||||
<MdOutlineArrowForwardIos onClick={handleNavigateToPage} /> {t("header.edit_question")}
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div className="exercise_add">
|
|
||||||
<Formik
|
|
||||||
onSubmit={handleSubmit}
|
|
||||||
initialValues={getInitialValuesBase(objectToEdit)}
|
|
||||||
validationSchema={getValidationSchemaBase}
|
|
||||||
enableReinitialize
|
|
||||||
>
|
|
||||||
{({ values,isValid,handleSubmit }) => (
|
|
||||||
|
|
||||||
<Form className="w-100">
|
|
||||||
<main className="w-100 exercise_add_main">
|
|
||||||
{/* <Header/> */}
|
|
||||||
<header className="exercise_add_header mb-4">
|
|
||||||
<div>
|
|
||||||
{t("practical.edit")} {t("models.exercise")}{" "}
|
|
||||||
</div>
|
|
||||||
<div className="SettingEdit">
|
|
||||||
<Popover trigger="click" content={contentSetting}>
|
|
||||||
<SettingFilled/>
|
|
||||||
|
|
||||||
</Popover>
|
|
||||||
<div>{t("header.exercise")}</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
<BaseForm />
|
|
||||||
<div className="exercise_add_buttons">
|
|
||||||
<div onClick={handleCancel}>{t("practical.back")}</div>
|
|
||||||
<button disabled={Loading} className="relative" type="button"
|
|
||||||
onClick={()=>{handleValidateBaseQuestion(values,isValid,handleSubmit) }}
|
|
||||||
onSubmit={()=>{handleValidateBaseQuestion(values,isValid,handleSubmit) }}
|
|
||||||
> {t("practical.edit")}
|
|
||||||
|
|
||||||
{Loading && (
|
|
||||||
<span className="Spinier_Div">
|
|
||||||
<Spin />
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
</Form>
|
|
||||||
)}
|
|
||||||
</Formik>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<FormContainer t={t} Loading={Loading} handleSubmit={handleSubmit} handleValidateSingleQuestion={handleValidateSingleQuestion} objectToEdit={objectToEdit} />
|
||||||
<div className="QuestionPractical">
|
|
||||||
<header>
|
|
||||||
<MdOutlineArrowForwardIos onClick={handleNavigateToPage} /> {t("header.edit_question")}
|
|
||||||
</header>
|
|
||||||
<div className="exercise_add">
|
|
||||||
|
|
||||||
<Formik
|
|
||||||
enableReinitialize={true}
|
|
||||||
initialValues={getInitialValues(objectToEdit)}
|
|
||||||
validationSchema={getValidationSchema}
|
|
||||||
onSubmit={(values) => {
|
|
||||||
handleSubmit(values);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{({ values , dirty,isValid,handleSubmit }) => (
|
|
||||||
<Form className="w-100">
|
|
||||||
<main className="w-100 exercise_add_main">
|
|
||||||
{/* <Header/> */}
|
|
||||||
<header className="exercise_add_header mb-4">
|
|
||||||
<div>
|
|
||||||
{t("practical.edit")} {t("models.exercise")}{" "}
|
|
||||||
</div>
|
|
||||||
<div className="SettingEdit">
|
|
||||||
|
|
||||||
<Popover trigger="click" content={contentSetting}>
|
|
||||||
<SettingFilled/>
|
|
||||||
|
|
||||||
</Popover>
|
|
||||||
<div>{t("header.exercise")}</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
<ModelForm />
|
|
||||||
<div className="exercise_add_buttons">
|
|
||||||
<div onClick={handleCancel}>{t("practical.back")}</div>
|
|
||||||
<div
|
|
||||||
className="relative"
|
|
||||||
onClick={()=>{ Loading ? ()=>{} : handleValidateSingleQuestion(values,isValid,handleSubmit) }}
|
|
||||||
> {t("practical.edit")}
|
|
||||||
{Loading && (
|
|
||||||
<span className="Spinier_Div">
|
|
||||||
<Spin />
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
</Form>
|
|
||||||
)}
|
|
||||||
</Formik>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
72
src/Pages/Admin/question/Model/AddForm/BaseForm.tsx
Normal file
72
src/Pages/Admin/question/Model/AddForm/BaseForm.tsx
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
import { Form, Formik, useFormikContext } from 'formik'
|
||||||
|
import React from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { MdOutlineArrowForwardIos } from 'react-icons/md'
|
||||||
|
import { getInitialValuesBase, getValidationSchemaBase } from '../../formUtil'
|
||||||
|
import Header from '../../../../../Components/exercise/Header'
|
||||||
|
import { useNavigate } from 'react-router-dom'
|
||||||
|
import { Spin } from 'antd'
|
||||||
|
import BaseForm from "../../Model/Malty/Form";
|
||||||
|
|
||||||
|
const BaseFormContainer = ({handleFormSubmit,Loading,handleValidateBaseQuestion}:{handleFormSubmit:any,Loading:any,handleValidateBaseQuestion:any}) => {
|
||||||
|
const [t] = useTranslation()
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const handleNavigateToPage = () => {
|
||||||
|
const cleanedUrl = location.pathname?.replace("/Question/add", "");
|
||||||
|
navigate(cleanedUrl);
|
||||||
|
};
|
||||||
|
const handleCancel = () => {
|
||||||
|
navigate(-1);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="QuestionPractical">
|
||||||
|
<header>
|
||||||
|
<MdOutlineArrowForwardIos onClick={handleNavigateToPage} /> {t("header.add_new_question")}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div className="exercise_add">
|
||||||
|
<Formik
|
||||||
|
onSubmit={handleFormSubmit}
|
||||||
|
initialValues={getInitialValuesBase({} as any)}
|
||||||
|
validationSchema={getValidationSchemaBase}
|
||||||
|
enableReinitialize
|
||||||
|
|
||||||
|
>
|
||||||
|
{({ values,isValid,handleSubmit ,dirty}) => (
|
||||||
|
|
||||||
|
<Form className="w-100">
|
||||||
|
<main className="w-100 exercise_add_main">
|
||||||
|
<Header />
|
||||||
|
<BaseForm />
|
||||||
|
|
||||||
|
<div className="exercise_add_buttons">
|
||||||
|
<div onClick={handleCancel}>{t("practical.back")}</div>
|
||||||
|
<button disabled={Loading} className={`relative ${dirty ? "" : "disabled"}`} type="button"
|
||||||
|
onClick={()=>{handleValidateBaseQuestion(values,isValid,handleSubmit,t) }}
|
||||||
|
>
|
||||||
|
{t("practical.add")}
|
||||||
|
|
||||||
|
{Loading && (
|
||||||
|
<span className="Spinier_Div">
|
||||||
|
<Spin />
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</Form>
|
||||||
|
)}
|
||||||
|
</Formik>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BaseFormContainer
|
||||||
72
src/Pages/Admin/question/Model/AddForm/Form.tsx
Normal file
72
src/Pages/Admin/question/Model/AddForm/Form.tsx
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
import { Form, Formik, useFormikContext } from 'formik'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { MdOutlineArrowForwardIos } from 'react-icons/md'
|
||||||
|
import { getInitialValues, getValidationSchema } from '../../formUtil'
|
||||||
|
import Header from '../../../../../Components/exercise/Header'
|
||||||
|
import { useNavigate } from 'react-router-dom'
|
||||||
|
import { Spin } from 'antd'
|
||||||
|
import ModelForm from "../../Model/ModelForm";
|
||||||
|
|
||||||
|
const FormContainer = ({handleFormSubmit,Loading,handleValidateSingleQuestion}:{handleFormSubmit:any,Loading:any,handleValidateSingleQuestion:any}) => {
|
||||||
|
const [t] = useTranslation()
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const handleNavigateToPage = () => {
|
||||||
|
const cleanedUrl = location.pathname?.replace("/Question/add", "");
|
||||||
|
navigate(cleanedUrl);
|
||||||
|
};
|
||||||
|
const handleCancel = () => {
|
||||||
|
navigate(-1);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="QuestionPractical">
|
||||||
|
<header>
|
||||||
|
<MdOutlineArrowForwardIos onClick={handleNavigateToPage} /> {t("header.add_new_question")}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div className="exercise_add">
|
||||||
|
<Formik
|
||||||
|
enableReinitialize={true}
|
||||||
|
initialValues={getInitialValues({} as any)}
|
||||||
|
validationSchema={getValidationSchema}
|
||||||
|
validateOnMount={true}
|
||||||
|
onSubmit={(values) => {
|
||||||
|
handleFormSubmit(values);
|
||||||
|
}}
|
||||||
|
|
||||||
|
>
|
||||||
|
{({ values,isValid ,handleSubmit,dirty}) => (
|
||||||
|
<Form className="w-100">
|
||||||
|
<main className="w-100 exercise_add_main">
|
||||||
|
<Header />
|
||||||
|
<ModelForm />
|
||||||
|
|
||||||
|
<div className="exercise_add_buttons">
|
||||||
|
<div onClick={handleCancel}>{t("practical.back")}</div>
|
||||||
|
<div
|
||||||
|
className={`relative ${dirty ? "" : "disabled"}`}
|
||||||
|
onClick={()=>{ Loading ? ()=>{} : handleValidateSingleQuestion(values,isValid,handleSubmit,t) }}
|
||||||
|
>
|
||||||
|
{t("practical.add")}
|
||||||
|
|
||||||
|
{Loading && (
|
||||||
|
<span className="Spinier_Div">
|
||||||
|
<Spin />
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</Form>
|
||||||
|
)}
|
||||||
|
</Formik>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FormContainer
|
||||||
100
src/Pages/Admin/question/Model/AddForm/ValidationFn.ts
Normal file
100
src/Pages/Admin/question/Model/AddForm/ValidationFn.ts
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
import { toast } from "react-toastify";
|
||||||
|
|
||||||
|
export const handleValidateSingleQuestion = (values:any,isValid:boolean,handleSubmit:any,t:any)=>{
|
||||||
|
const haveMoreThanOneAnswer = values?.answers?.length > 1;
|
||||||
|
const haveOneAnswerRight = haveMoreThanOneAnswer && values?.answers?.some((item:any)=> item?.isCorrect === 1 || item.isCorrect === true )
|
||||||
|
const haveImageOrContent = haveOneAnswerRight && values?.answers?.some((item:any)=> !(item?.content) && !(item.content_image) )
|
||||||
|
const content = values.content ;
|
||||||
|
const content_image = values.content_image ;
|
||||||
|
const haveContentOrContentImage = !!content || !!content_image ;
|
||||||
|
console.log(haveImageOrContent,"haveImageOrContent");
|
||||||
|
if(!haveContentOrContentImage){
|
||||||
|
toast.error(`${t("validation.one_of_image_and_content_should_be_enter_in_question")}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!haveMoreThanOneAnswer){
|
||||||
|
toast.error(t("validation.it_should_have_more_than_one_answers")) ;
|
||||||
|
return false ;
|
||||||
|
}
|
||||||
|
if(!haveOneAnswerRight){
|
||||||
|
toast.error(t("validation.it_should_have_more_than_one_correct_answers")) ;
|
||||||
|
return false ;
|
||||||
|
}
|
||||||
|
if(haveImageOrContent){
|
||||||
|
toast.error(t("validation.one_of_image_and_content_should_be_enter_in_answer"))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(1);
|
||||||
|
|
||||||
|
if(isValid){
|
||||||
|
handleSubmit(values)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
export const handleValidateBaseQuestion = (values: any,isValid:boolean,handleSubmit:any,t:any) => {
|
||||||
|
const content = values.content ;
|
||||||
|
const content_image = values.content_image ;
|
||||||
|
const haveContentOrContentImage = !!content || !!content_image ;
|
||||||
|
console.log(2);
|
||||||
|
|
||||||
|
if(!haveContentOrContentImage){
|
||||||
|
toast.error(`${t("validation.one_of_image_and_content_should_be_enter_in_question")}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
console.log(1);
|
||||||
|
|
||||||
|
const isValidate = values?.Questions?.every((Question: any, QuestionsIndex: number) => {
|
||||||
|
|
||||||
|
|
||||||
|
const content = Question.content ;
|
||||||
|
const content_image = Question.content_image ;
|
||||||
|
const haveContentOrContentImage = !!content || !!content_image ;
|
||||||
|
if(!haveContentOrContentImage){
|
||||||
|
toast.error(`${t("validation.one_of_image_and_content_should_be_enter_in_question")}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//// answers
|
||||||
|
const answers = Question?.answers;
|
||||||
|
const haveAnswers = answers?.length > 0;
|
||||||
|
const haveMoreThanOneAnswer = haveAnswers && answers?.length > 1;
|
||||||
|
const haveOneAnswerRight = haveMoreThanOneAnswer && answers?.some((item: any) => item?.isCorrect === 1 || item.isCorrect === true);
|
||||||
|
const haveImageOrContent = haveOneAnswerRight && answers?.some((item:any)=> !(item?.content) && !(item.content_image) )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (!haveAnswers) {
|
||||||
|
toast.error(t("validation.it_should_have_more_than_one_answers"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!haveMoreThanOneAnswer) {
|
||||||
|
toast.error(t("validation.it_should_have_more_than_one_answers"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!haveOneAnswerRight) {
|
||||||
|
toast.error(t("validation.it_should_have_more_than_one_correct_answers"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(haveImageOrContent){
|
||||||
|
toast.error(t("validation.one_of_image_and_content_should_be_enter_in_answer"))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(1);
|
||||||
|
|
||||||
|
if(isValid && isValidate){
|
||||||
|
console.log(2);
|
||||||
|
handleSubmit(values)
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
108
src/Pages/Admin/question/Model/EditForm/BaseFormContainer.tsx
Normal file
108
src/Pages/Admin/question/Model/EditForm/BaseFormContainer.tsx
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
import { Form, Formik } from 'formik';
|
||||||
|
import React from 'react'
|
||||||
|
import { MdOutlineArrowForwardIos } from 'react-icons/md';
|
||||||
|
import { useLocation, useNavigate } from 'react-router-dom';
|
||||||
|
import { getInitialValuesBase, getValidationSchemaBase } from '../../formUtil';
|
||||||
|
import { Checkbox, Popover, Spin } from 'antd';
|
||||||
|
import { SettingFilled } from '@ant-design/icons';
|
||||||
|
import { CheckboxProps } from 'antd/lib';
|
||||||
|
import { LocalStorageEnum } from '../../../../../enums/LocalStorageEnum';
|
||||||
|
import { useObjectToEdit } from '../../../../../zustand/ObjectToEditState';
|
||||||
|
import ModelForm from "../../Model/Malty/Form";
|
||||||
|
|
||||||
|
const BaseFormContainer = ({objectToEdit,handleSubmit,Loading,handleValidateBaseQuestion,t}:{objectToEdit:any,handleSubmit:any,Loading:any,handleValidateBaseQuestion:any,t:any}) => {
|
||||||
|
const location = useLocation();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { ShowHint,setShowHint , ShowLatexOption,setShowLatexOption } =
|
||||||
|
useObjectToEdit();
|
||||||
|
const handleCancel = () => {
|
||||||
|
navigate(-1);
|
||||||
|
};
|
||||||
|
const handleNavigateToPage = () => {
|
||||||
|
const cleanedUrl = location.pathname.replace(/\/Question\/\d+$/, "");
|
||||||
|
navigate(cleanedUrl);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onChangeHint: CheckboxProps['onChange'] = (e) => {
|
||||||
|
setShowHint(e.target.checked);
|
||||||
|
localStorage?.setItem(LocalStorageEnum.HINT_INPUT,e.target.checked ? "true" : "false" )
|
||||||
|
};
|
||||||
|
|
||||||
|
const onChangeLatexOption: CheckboxProps['onChange'] = (e) => {
|
||||||
|
setShowLatexOption(e.target.checked);
|
||||||
|
localStorage?.setItem(LocalStorageEnum.LATEX_OPTION_INPUT,e.target.checked ? "true" : "false" )
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const contentSetting = (
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<Checkbox checked={ShowHint} onChange={onChangeHint}>
|
||||||
|
{ t("header.show_hint")}
|
||||||
|
</Checkbox>
|
||||||
|
|
||||||
|
<Checkbox checked={ShowLatexOption} onChange={onChangeLatexOption}>
|
||||||
|
{ t("header.show_MMl")}
|
||||||
|
</Checkbox>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="QuestionPractical">
|
||||||
|
<header>
|
||||||
|
<MdOutlineArrowForwardIos onClick={handleNavigateToPage} /> {t("header.edit_question")}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div className="exercise_add">
|
||||||
|
<Formik
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
initialValues={getInitialValuesBase(objectToEdit)}
|
||||||
|
validationSchema={getValidationSchemaBase}
|
||||||
|
enableReinitialize
|
||||||
|
>
|
||||||
|
{({ values,isValid,handleSubmit,dirty }) => (
|
||||||
|
|
||||||
|
<Form className="w-100">
|
||||||
|
<main className="w-100 exercise_add_main">
|
||||||
|
{/* <Header/> */}
|
||||||
|
<header className="exercise_add_header mb-4">
|
||||||
|
<div>
|
||||||
|
{t("practical.edit")} {t("models.exercise")}{" "}
|
||||||
|
</div>
|
||||||
|
<div className="SettingEdit">
|
||||||
|
<Popover trigger="click" content={contentSetting}>
|
||||||
|
<SettingFilled/>
|
||||||
|
|
||||||
|
</Popover>
|
||||||
|
<div>{t("header.exercise")}</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<ModelForm />
|
||||||
|
<div className="exercise_add_buttons">
|
||||||
|
<div onClick={handleCancel}>{t("practical.back")}</div>
|
||||||
|
<button disabled={Loading} className={`relative ${dirty ? "" : "disabled"}`} type="button"
|
||||||
|
onClick={()=>{handleValidateBaseQuestion(values,isValid,handleSubmit) }}
|
||||||
|
onSubmit={()=>{handleValidateBaseQuestion(values,isValid,handleSubmit) }}
|
||||||
|
> {t("practical.edit")}
|
||||||
|
|
||||||
|
{Loading && (
|
||||||
|
<span className="Spinier_Div">
|
||||||
|
<Spin />
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</Form>
|
||||||
|
)}
|
||||||
|
</Formik>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BaseFormContainer
|
||||||
110
src/Pages/Admin/question/Model/EditForm/FormContainer.tsx
Normal file
110
src/Pages/Admin/question/Model/EditForm/FormContainer.tsx
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
import { Form, Formik } from 'formik';
|
||||||
|
import React from 'react'
|
||||||
|
import { MdOutlineArrowForwardIos } from 'react-icons/md';
|
||||||
|
import { useLocation, useNavigate } from 'react-router-dom';
|
||||||
|
import { getInitialValues, getValidationSchema } from '../../formUtil';
|
||||||
|
import { Checkbox, Popover, Spin } from 'antd';
|
||||||
|
import { SettingFilled } from '@ant-design/icons';
|
||||||
|
import { CheckboxProps } from 'antd/lib';
|
||||||
|
import { LocalStorageEnum } from '../../../../../enums/LocalStorageEnum';
|
||||||
|
import { useObjectToEdit } from '../../../../../zustand/ObjectToEditState';
|
||||||
|
import ModelForm from "../../Model/ModelForm";
|
||||||
|
|
||||||
|
const FormContainer = ({objectToEdit,handleSubmit,Loading,handleValidateSingleQuestion,t}:{objectToEdit:any,handleSubmit:any,Loading:any,handleValidateSingleQuestion:any,t:any}) => {
|
||||||
|
const location = useLocation();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { ShowHint,setShowHint , ShowLatexOption,setShowLatexOption } =
|
||||||
|
useObjectToEdit();
|
||||||
|
const handleCancel = () => {
|
||||||
|
navigate(-1);
|
||||||
|
};
|
||||||
|
const handleNavigateToPage = () => {
|
||||||
|
const cleanedUrl = location.pathname.replace(/\/Question\/\d+$/, "");
|
||||||
|
navigate(cleanedUrl);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onChangeHint: CheckboxProps['onChange'] = (e) => {
|
||||||
|
setShowHint(e.target.checked);
|
||||||
|
localStorage?.setItem(LocalStorageEnum.HINT_INPUT,e.target.checked ? "true" : "false" )
|
||||||
|
};
|
||||||
|
|
||||||
|
const onChangeLatexOption: CheckboxProps['onChange'] = (e) => {
|
||||||
|
setShowLatexOption(e.target.checked);
|
||||||
|
localStorage?.setItem(LocalStorageEnum.LATEX_OPTION_INPUT,e.target.checked ? "true" : "false" )
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const contentSetting = (
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<Checkbox checked={ShowHint} onChange={onChangeHint}>
|
||||||
|
{ t("header.show_hint")}
|
||||||
|
</Checkbox>
|
||||||
|
|
||||||
|
<Checkbox checked={ShowLatexOption} onChange={onChangeLatexOption}>
|
||||||
|
{ t("header.show_MMl")}
|
||||||
|
</Checkbox>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="QuestionPractical">
|
||||||
|
<header>
|
||||||
|
<MdOutlineArrowForwardIos onClick={handleNavigateToPage} /> {t("header.edit_question")}
|
||||||
|
</header>
|
||||||
|
<div className="exercise_add">
|
||||||
|
|
||||||
|
<Formik
|
||||||
|
enableReinitialize={true}
|
||||||
|
initialValues={getInitialValues(objectToEdit)}
|
||||||
|
validationSchema={getValidationSchema}
|
||||||
|
onSubmit={(values) => {
|
||||||
|
handleSubmit(values);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{({ values , dirty,isValid,handleSubmit }) => (
|
||||||
|
<Form className="w-100">
|
||||||
|
<main className="w-100 exercise_add_main">
|
||||||
|
{/* <Header/> */}
|
||||||
|
<header className="exercise_add_header mb-4">
|
||||||
|
<div>
|
||||||
|
{t("practical.edit")} {t("models.exercise")}{" "}
|
||||||
|
</div>
|
||||||
|
<div className="SettingEdit">
|
||||||
|
|
||||||
|
<Popover trigger="click" content={contentSetting}>
|
||||||
|
<SettingFilled/>
|
||||||
|
|
||||||
|
</Popover>
|
||||||
|
<div>{t("header.exercise")}</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<ModelForm />
|
||||||
|
<div className="exercise_add_buttons">
|
||||||
|
<div onClick={handleCancel}>{t("practical.back")}</div>
|
||||||
|
<div
|
||||||
|
className={`relative ${dirty ? "" : "disabled"}`}
|
||||||
|
onClick={()=>{ Loading ? ()=>{} : handleValidateSingleQuestion(values,isValid,handleSubmit,t) }}
|
||||||
|
> {t("practical.edit")}
|
||||||
|
{Loading && (
|
||||||
|
<span className="Spinier_Div">
|
||||||
|
<Spin />
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
</Form>
|
||||||
|
)}
|
||||||
|
</Formik>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FormContainer
|
||||||
100
src/Pages/Admin/question/Model/EditForm/ValidationFn.ts
Normal file
100
src/Pages/Admin/question/Model/EditForm/ValidationFn.ts
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
import { toast } from "react-toastify";
|
||||||
|
|
||||||
|
export const handleValidateSingleQuestion = (values:any,isValid:boolean,handleSubmit:any,t:any)=>{
|
||||||
|
const haveMoreThanOneAnswer = values?.answers?.length > 1;
|
||||||
|
const haveOneAnswerRight = haveMoreThanOneAnswer && values?.answers?.some((item:any)=> item?.isCorrect === 1 || item.isCorrect === true )
|
||||||
|
const haveImageOrContent = haveOneAnswerRight && values?.answers?.some((item:any)=> !(item?.content) && !(item.content_image) )
|
||||||
|
const content = values.content ;
|
||||||
|
const content_image = values.content_image ;
|
||||||
|
const haveContentOrContentImage = !!content || !!content_image ;
|
||||||
|
console.log(haveImageOrContent,"haveImageOrContent");
|
||||||
|
if(!haveContentOrContentImage){
|
||||||
|
toast.error(`${t("validation.one_of_image_and_content_should_be_enter_in_question")}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!haveMoreThanOneAnswer){
|
||||||
|
toast.error(t("validation.it_should_have_more_than_one_answers")) ;
|
||||||
|
return false ;
|
||||||
|
}
|
||||||
|
if(!haveOneAnswerRight){
|
||||||
|
toast.error(t("validation.it_should_have_more_than_one_correct_answers")) ;
|
||||||
|
return false ;
|
||||||
|
}
|
||||||
|
if(haveImageOrContent){
|
||||||
|
toast.error(t("validation.one_of_image_and_content_should_be_enter_in_answer"))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(1);
|
||||||
|
|
||||||
|
if(isValid){
|
||||||
|
handleSubmit(values)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
export const handleValidateBaseQuestion = (values: any,isValid:boolean,handleSubmit:any,t:any) => {
|
||||||
|
const content = values.content ;
|
||||||
|
const content_image = values.content_image ;
|
||||||
|
const haveContentOrContentImage = !!content || !!content_image ;
|
||||||
|
console.log(2);
|
||||||
|
|
||||||
|
if(!haveContentOrContentImage){
|
||||||
|
toast.error(`${t("validation.one_of_image_and_content_should_be_enter_in_question")}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
console.log(1);
|
||||||
|
|
||||||
|
const isValidate = values?.Questions?.every((Question: any, QuestionsIndex: number) => {
|
||||||
|
|
||||||
|
|
||||||
|
const content = Question.content ;
|
||||||
|
const content_image = Question.content_image ;
|
||||||
|
const haveContentOrContentImage = !!content || !!content_image ;
|
||||||
|
if(!haveContentOrContentImage){
|
||||||
|
toast.error(`${t("validation.one_of_image_and_content_should_be_enter_in_question")}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//// answers
|
||||||
|
const answers = Question?.answers;
|
||||||
|
const haveAnswers = answers?.length > 0;
|
||||||
|
const haveMoreThanOneAnswer = haveAnswers && answers?.length > 1;
|
||||||
|
const haveOneAnswerRight = haveMoreThanOneAnswer && answers?.some((item: any) => item?.isCorrect === 1 || item.isCorrect === true);
|
||||||
|
const haveImageOrContent = haveOneAnswerRight && answers?.some((item:any)=> !(item?.content) && !(item.content_image) )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (!haveAnswers) {
|
||||||
|
toast.error(t("validation.it_should_have_more_than_one_answers"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!haveMoreThanOneAnswer) {
|
||||||
|
toast.error(t("validation.it_should_have_more_than_one_answers"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!haveOneAnswerRight) {
|
||||||
|
toast.error(t("validation.it_should_have_more_than_one_correct_answers"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(haveImageOrContent){
|
||||||
|
toast.error(t("validation.one_of_image_and_content_should_be_enter_in_answer"))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(1);
|
||||||
|
|
||||||
|
if(isValid && isValidate){
|
||||||
|
console.log(2);
|
||||||
|
handleSubmit(values)
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
@ -21,7 +21,6 @@ const ChoiceFields = React.memo(
|
||||||
setFieldValue:any;
|
setFieldValue:any;
|
||||||
values:any
|
values:any
|
||||||
}) => {
|
}) => {
|
||||||
console.log(567)
|
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
const { ShowHint } = useObjectToEdit();
|
const { ShowHint } = useObjectToEdit();
|
||||||
const handleDeleteChoice = () => {
|
const handleDeleteChoice = () => {
|
||||||
|
|
@ -120,7 +119,6 @@ const ChoiceFields = React.memo(
|
||||||
}
|
}
|
||||||
, (prevProps, nextProps) => {
|
, (prevProps, nextProps) => {
|
||||||
console.log(prevProps.values?.Questions?.[prevProps?.parent_index]?.answers?.[prevProps?.index] === nextProps.values?.Questions?.[nextProps?.parent_index]?.answers?.[prevProps?.index]);
|
console.log(prevProps.values?.Questions?.[prevProps?.parent_index]?.answers?.[prevProps?.index] === nextProps.values?.Questions?.[nextProps?.parent_index]?.answers?.[prevProps?.index]);
|
||||||
console.log(2255);
|
|
||||||
|
|
||||||
return prevProps.values?.Questions?.[prevProps?.parent_index]?.answers?.[prevProps?.index] === nextProps.values?.Questions?.[nextProps?.parent_index]?.answers?.[prevProps?.index];
|
return prevProps.values?.Questions?.[prevProps?.parent_index]?.answers?.[prevProps?.index] === nextProps.values?.Questions?.[nextProps?.parent_index]?.answers?.[prevProps?.index];
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -113,8 +113,6 @@ const Choices = React.memo( ({setFieldValue ,values,parent_index }:any) => {
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}, (prevProps, nextProps) => {
|
}, (prevProps, nextProps) => {
|
||||||
console.log(prevProps.values?.Questions?.[prevProps?.parent_index]?.answers === nextProps.values?.Questions?.[nextProps?.parent_index]?.answers);
|
|
||||||
console.log(22);
|
|
||||||
|
|
||||||
return prevProps.values?.Questions?.[prevProps?.parent_index]?.answers === nextProps.values?.Questions?.[nextProps?.parent_index]?.answers;
|
return prevProps.values?.Questions?.[prevProps?.parent_index]?.answers === nextProps.values?.Questions?.[nextProps?.parent_index]?.answers;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import { CombinationKeyEnum } from "../../../../../enums/CombinationKeyEnum";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import MainInputs from "./components/MainInputs";
|
import MainInputs from "./components/MainInputs";
|
||||||
import Questions from "./components/Questions";
|
import Questions from "./components/Questions";
|
||||||
|
import useUnsavedChangesWarning from "../../../../../Hooks/useUnsavedChangesWarning";
|
||||||
|
|
||||||
const Form = () => {
|
const Form = () => {
|
||||||
const formik = useFormikContext<any>();
|
const formik = useFormikContext<any>();
|
||||||
|
|
@ -64,6 +65,8 @@ const Form = () => {
|
||||||
|
|
||||||
|
|
||||||
const lastQuestions = formik?.values?.Questions?.length - 1;
|
const lastQuestions = formik?.values?.Questions?.length - 1;
|
||||||
|
|
||||||
|
////////////// hooks
|
||||||
useKeyCombination(
|
useKeyCombination(
|
||||||
{ ctrlKey: true, shiftKey: true, code: CombinationKeyEnum.CHOICE },
|
{ ctrlKey: true, shiftKey: true, code: CombinationKeyEnum.CHOICE },
|
||||||
() => {
|
() => {
|
||||||
|
|
@ -77,8 +80,10 @@ const lastQuestions = formik?.values?.Questions?.length - 1;
|
||||||
handleAddQuestion(true);
|
handleAddQuestion(true);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
useUnsavedChangesWarning(formik.dirty);
|
||||||
|
|
||||||
|
|
||||||
|
//////////////
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (Success) {
|
if (Success) {
|
||||||
formik.resetForm()
|
formik.resetForm()
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import { CombinationKeyEnum } from "../../../../enums/CombinationKeyEnum";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import LaTeXInputMemo from "../../../../Components/LatextInput/LaTeXInputMemo";
|
import LaTeXInputMemo from "../../../../Components/LatextInput/LaTeXInputMemo";
|
||||||
import ImageBoxFieldMemo from "../../../../Components/CustomFields/ImageBoxField/ImageBoxFieldMemo";
|
import ImageBoxFieldMemo from "../../../../Components/CustomFields/ImageBoxField/ImageBoxFieldMemo";
|
||||||
|
import useUnsavedChangesWarning from "../../../../Hooks/useUnsavedChangesWarning";
|
||||||
|
|
||||||
const Form = () => {
|
const Form = () => {
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
|
|
@ -33,6 +34,10 @@ const Form = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
////////////// hooks
|
||||||
|
|
||||||
|
|
||||||
useKeyCombination(
|
useKeyCombination(
|
||||||
{ ctrlKey: true, shiftKey: true, code: CombinationKeyEnum.CHOICE },
|
{ ctrlKey: true, shiftKey: true, code: CombinationKeyEnum.CHOICE },
|
||||||
() => {
|
() => {
|
||||||
|
|
@ -40,6 +45,10 @@ const Form = () => {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
useUnsavedChangesWarning(formik.dirty);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (Success) {
|
if (Success) {
|
||||||
formik.resetForm()
|
formik.resetForm()
|
||||||
|
|
@ -47,8 +56,6 @@ const Form = () => {
|
||||||
}
|
}
|
||||||
}, [Success]);
|
}, [Success]);
|
||||||
|
|
||||||
console.log(formik.errors);
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Row className="w-100 exercise_form_container">
|
<Row className="w-100 exercise_form_container">
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,6 @@ const Dummy = () => {
|
||||||
return (
|
return (
|
||||||
<div className="DummyHomePage">
|
<div className="DummyHomePage">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ const LaTeXInputMemo: React.FC<any> = React.memo(({ field ,form, label, ...prop
|
||||||
const { setFieldValue } = form;
|
const { setFieldValue } = form;
|
||||||
const [curCentValue, setCurrentValue] = useState(value)
|
const [curCentValue, setCurrentValue] = useState(value)
|
||||||
const handleChangeInput = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
const handleChangeInput = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||||
setFieldValue(name, e.target.value);
|
// setFieldValue(name, e.target.value);
|
||||||
setCurrentValue(e.target.value)
|
setCurrentValue(e.target.value)
|
||||||
};
|
};
|
||||||
console.log(name,"name");
|
console.log(name,"name");
|
||||||
|
|
@ -24,6 +24,7 @@ const LaTeXInputMemo: React.FC<any> = React.memo(({ field ,form, label, ...prop
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<div className='LaTeXInputArea'>
|
<div className='LaTeXInputArea'>
|
||||||
|
|
||||||
<TextArea
|
<TextArea
|
||||||
size="large"
|
size="large"
|
||||||
showCount
|
showCount
|
||||||
|
|
|
||||||
|
|
@ -115,3 +115,6 @@ svg{
|
||||||
.LaTeXRenderer{
|
.LaTeXRenderer{
|
||||||
direction: ltr;
|
direction: ltr;
|
||||||
}
|
}
|
||||||
|
.ant-input,.LaTeXInputArea,input{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -101,3 +101,8 @@
|
||||||
background: transparent !important;
|
background: transparent !important;
|
||||||
color: #fff !important;
|
color: #fff !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.disabled{
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
@ -52,7 +52,8 @@
|
||||||
"File_size_exceeds_2_MB_limit.":"حجم الملف يتجاوز الحد الأقصى البالغ 2 ميجابايت",
|
"File_size_exceeds_2_MB_limit.":"حجم الملف يتجاوز الحد الأقصى البالغ 2 ميجابايت",
|
||||||
"one_of_image_and_content_should_be_enter_in_answer":"يجب إدخال صورة أو محتوى واحد على الأقل في الاجابة",
|
"one_of_image_and_content_should_be_enter_in_answer":"يجب إدخال صورة أو محتوى واحد على الأقل في الاجابة",
|
||||||
"one_of_image_and_content_should_be_enter_in_question":"يجب إدخال صورة أو محتوى واحد على الأقل في السؤال",
|
"one_of_image_and_content_should_be_enter_in_question":"يجب إدخال صورة أو محتوى واحد على الأقل في السؤال",
|
||||||
"that_is_not_a_valid_mml":"هذا ليس mml صالح"
|
"that_is_not_a_valid_mml":"هذا ليس mml صالح",
|
||||||
|
"Are_you_sure_you_want_to_leave_Your_changes_may_not_be_saved":"هل أنت متأكد من أنك تريد المغادرة ؟ قد لا يتم حفظ التغييرات التي أجريتها"
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
"register_students": "تسجيل الطلاب",
|
"register_students": "تسجيل الطلاب",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user