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 { useFormikContext } from 'formik';
|
||||
import React, { Suspense, useEffect, useState } from 'react';
|
||||
import { parseTextAndLatex } from '../../utils/parseTextAndLatex';
|
||||
import LatexPreview from '../CustomFields/MathComponent';
|
||||
|
|
@ -49,15 +48,24 @@ const LaTeXInputMemo: React.FC<any> = React.memo(({ field ,form, label, ...prop
|
|||
setCurrentValue(e.target.value)
|
||||
};
|
||||
const onBlur = ()=>{
|
||||
|
||||
setFieldValue(name, curCentValue);
|
||||
if (curCentValue !== value) {
|
||||
setFieldValue(name, curCentValue);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if(Success){
|
||||
setCurrentValue(null)
|
||||
}
|
||||
}, [Success])
|
||||
|
||||
useEffect(() => {
|
||||
if(value){
|
||||
setCurrentValue(value)
|
||||
}
|
||||
}, [value])
|
||||
|
||||
|
||||
const isError = !!touched?.[name] && !!errors?.[name];
|
||||
const errorMessage = isError ? errors?.[name] as string ?? "" : "" ;
|
||||
return (
|
||||
|
|
@ -93,7 +101,7 @@ const LaTeXInputMemo: React.FC<any> = React.memo(({ field ,form, label, ...prop
|
|||
{Preview?.map((item: any, index: number) => {
|
||||
if (item?.isLatex) {
|
||||
return (
|
||||
<div key={index} onClick={() => handleEditModal(item)} className='LatexPreview'>
|
||||
<div dir='ltr' key={index} onClick={() => handleEditModal(item)} className='LatexPreview'>
|
||||
<LatexPreview Latex={item?.text} />
|
||||
</div>
|
||||
);
|
||||
|
|
@ -104,9 +112,10 @@ const LaTeXInputMemo: React.FC<any> = React.memo(({ field ,form, label, ...prop
|
|||
)}
|
||||
</div>
|
||||
|
||||
<AddLazyModal name={name} Latex={Latex} isModalOpen={isModalOpen} setIsModalOpen={setIsModalOpen} setLatex={setLatex} setCurrentValue={setCurrentValue} />
|
||||
<EditLazyModal name={name} Latex={Latex} isModalOpen={isEditModalOpen} setIsModalOpen={setIsEditModalOpen} setLatex={setLatex} />
|
||||
<Suspense fallback={<SpinContainer />}>
|
||||
<Suspense fallback={<SpinContainer />}>
|
||||
<AddLazyModal name={name} Latex={Latex} isModalOpen={isModalOpen} setIsModalOpen={setIsModalOpen} setLatex={setLatex} setCurrentValue={setCurrentValue} />
|
||||
<EditLazyModal name={name} Latex={Latex} isModalOpen={isEditModalOpen} setIsModalOpen={setIsEditModalOpen} setLatex={setLatex} />
|
||||
|
||||
</Suspense>
|
||||
</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) {
|
||||
currentElement.focus(); // Set focus on the element
|
||||
}
|
||||
console.log(currentElement,"currentElement");
|
||||
}, [lastElementIndex])
|
||||
|
||||
// console.log(formik?.values);
|
||||
|
|
|
|||
|
|
@ -167,7 +167,6 @@ const DrapableTable: React.FC = () => {
|
|||
const [t] = useTranslation();
|
||||
const columns = useColumns();
|
||||
const sortedDataSource = dataSource.sort((a, b) => a.order - b.order);
|
||||
console.log(sortedDataSource, "sortedDataSource");
|
||||
|
||||
return (
|
||||
<DndContext modifiers={[restrictToVerticalAxis]} onDragEnd={onDragEnd}>
|
||||
|
|
|
|||
|
|
@ -1,38 +1,26 @@
|
|||
import React, { useEffect } from "react";
|
||||
import { Spin } from "antd";
|
||||
import {
|
||||
getInitialValues,
|
||||
getValidationSchema,
|
||||
getInitialValuesBase,
|
||||
getValidationSchemaBase,
|
||||
processTags,
|
||||
} from "./formUtil";
|
||||
import { useAddQuestion, useAddQuestionAsync } from "../../../api/Question";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useLocation, useNavigate, useParams } from "react-router-dom";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { ParamsEnum } from "../../../enums/params";
|
||||
import { useObjectToEdit } from "../../../zustand/ObjectToEditState";
|
||||
|
||||
import Header from "../../../Components/exercise/Header";
|
||||
import { Question } from "../../../types/Item";
|
||||
import BaseForm from "./Model/Malty/Form";
|
||||
import ModelForm from "./Model/ModelForm";
|
||||
import { toast } from "react-toastify";
|
||||
import { Form, Formik } from "formik";
|
||||
import { MdOutlineArrowForwardIos } from "react-icons/md";
|
||||
import BaseFormContainer from "./Model/AddForm/BaseForm";
|
||||
import FormContainer from "./Model/AddForm/Form";
|
||||
import { handleValidateBaseQuestion, handleValidateSingleQuestion } from "./Model/AddForm/ValidationFn";
|
||||
import useUnsavedChangesWarning from "../../../Hooks/useUnsavedChangesWarning";
|
||||
import { useFormikContext } from "formik";
|
||||
|
||||
const AddPage: React.FC = () => {
|
||||
const location = useLocation();
|
||||
|
||||
const { mutateAsync,isLoading:LoadingAsync } = useAddQuestionAsync();
|
||||
const { mutateAsync, isLoading: LoadingAsync } = useAddQuestionAsync();
|
||||
const { mutate, isLoading, isSuccess } = useAddQuestion();
|
||||
const { isBseQuestion, setTagsSearch, setSuccess } =
|
||||
useObjectToEdit();
|
||||
|
||||
const [t] = useTranslation();
|
||||
const { isBseQuestion, setTagsSearch, setSuccess } = useObjectToEdit();
|
||||
const { subject_id, lesson_id } = useParams<ParamsEnum>();
|
||||
|
||||
const handleFormSubmit = ( values: any) => {
|
||||
const handleFormSubmit = (values: any) => {
|
||||
const DataToSend = structuredClone(values);
|
||||
setTagsSearch(null);
|
||||
|
||||
|
|
@ -63,7 +51,7 @@ const AddPage: React.FC = () => {
|
|||
...item,
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
mutate({
|
||||
...item,
|
||||
parent_id: newBseQuestionId,
|
||||
|
|
@ -99,216 +87,27 @@ const AddPage: React.FC = () => {
|
|||
mutate(NewQuestion);
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (isSuccess) {
|
||||
setSuccess(true);
|
||||
|
||||
}
|
||||
}, [isSuccess]);
|
||||
|
||||
if (isBseQuestion) {
|
||||
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 }) => (
|
||||
|
||||
<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>
|
||||
<BaseFormContainer Loading={Loading} handleFormSubmit={handleFormSubmit} handleValidateBaseQuestion={handleValidateBaseQuestion} />
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
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}) => (
|
||||
<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>
|
||||
<FormContainer Loading={Loading} handleFormSubmit={handleFormSubmit} handleValidateSingleQuestion={handleValidateSingleQuestion} />
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,5 @@
|
|||
import React, { useEffect } from "react";
|
||||
import { Checkbox, Modal, Popover, Spin } from "antd";
|
||||
import {
|
||||
getInitialValues,
|
||||
getValidationSchema,
|
||||
getInitialValuesBase,
|
||||
getValidationSchemaBase,
|
||||
processTags,
|
||||
} from "./formUtil";
|
||||
import {
|
||||
|
|
@ -19,25 +14,20 @@ import { ParamsEnum } from "../../../enums/params";
|
|||
import { useObjectToEdit } from "../../../zustand/ObjectToEditState";
|
||||
import { removeStringKeys } from "../../../utils/removeStringKeys";
|
||||
import SpinContainer from "../../../Components/Layout/SpinContainer";
|
||||
import ModelForm from "./Model/ModelForm";
|
||||
import BaseForm from "./Model/Malty/Form";
|
||||
import { Question } from "../../../types/Item";
|
||||
import { toast } from "react-toastify";
|
||||
import { deletePathSegments } from "../../../utils/deletePathSegments";
|
||||
import { Form, Formik } from "formik";
|
||||
import { MdOutlineArrowForwardIos } from "react-icons/md";
|
||||
import { SettingFilled } from "@ant-design/icons";
|
||||
import { CheckboxProps } from "antd/lib";
|
||||
import { LocalStorageEnum } from "../../../enums/LocalStorageEnum";
|
||||
import BaseFormContainer from "./Model/EditForm/BaseFormContainer";
|
||||
import FormContainer from "./Model/EditForm/FormContainer";
|
||||
|
||||
const EditPage: React.FC = () => {
|
||||
const { subject_id, lesson_id, question_id } = useParams<ParamsEnum>();
|
||||
const { isBseQuestion, setIsBseQuestion, setTagsSearch, DeletedQuestions , ShowHint,setShowHint , ShowLatexOption,setShowLatexOption } =
|
||||
const { isBseQuestion, setIsBseQuestion, setTagsSearch, DeletedQuestions, ShowHint, setShowHint, ShowLatexOption, setShowLatexOption } =
|
||||
useObjectToEdit();
|
||||
|
||||
const { mutate, isSuccess, isLoading } = useUpdateQuestion();
|
||||
const { mutate: DeleteQuestion } = useDeleteQuestion();
|
||||
const { mutate: mutateAdd , isLoading:LoadingAsync } = useAddQuestion();
|
||||
const { mutate: mutateAdd, isLoading: LoadingAsync } = useAddQuestion();
|
||||
|
||||
const { data, isLoading: dataLoading } = useGetAllQuestion({
|
||||
show: question_id,
|
||||
|
|
@ -46,7 +36,7 @@ const EditPage: React.FC = () => {
|
|||
const { data: Questions, isLoading: QuestionsDataLoading } =
|
||||
useGetAllQuestion({
|
||||
parent_id: question_id,
|
||||
isPaginated:false
|
||||
isPaginated: false
|
||||
});
|
||||
|
||||
const objectToEdit = { ...data?.data, Questions: Questions?.data };
|
||||
|
|
@ -62,7 +52,7 @@ const EditPage: React.FC = () => {
|
|||
const handleSubmit = (values: any) => {
|
||||
const DataToSend = structuredClone(values);
|
||||
setTagsSearch(null);
|
||||
|
||||
|
||||
if (isBseQuestion) {
|
||||
|
||||
const UpdateBseQuestion = {
|
||||
|
|
@ -79,7 +69,7 @@ const EditPage: React.FC = () => {
|
|||
console.log(DeletedQuestions, "DeletedQuestions");
|
||||
console.log(UpdateBseQuestion);
|
||||
|
||||
// mutate(UpdateBseQuestion);
|
||||
mutate(UpdateBseQuestion);
|
||||
|
||||
DeletedQuestions?.map((item: any) => {
|
||||
DeleteQuestion({ id: item?.id });
|
||||
|
|
@ -93,8 +83,8 @@ const EditPage: React.FC = () => {
|
|||
if (item?.id) {
|
||||
const itemToSend = structuredClone(item);
|
||||
const keysToRemove = ["content_image"];
|
||||
console.log(itemToSend,"itemToSend");
|
||||
|
||||
console.log(itemToSend, "itemToSend");
|
||||
|
||||
const updatedObject = removeStringKeys(itemToSend, keysToRemove);
|
||||
console.log(updatedObject, "updatedObject");
|
||||
|
||||
|
|
@ -102,14 +92,14 @@ const EditPage: React.FC = () => {
|
|||
const oldAnswers = [] as any;
|
||||
const newAnswers = [] as any;
|
||||
|
||||
if(updatedObject?.content_image === null){
|
||||
if (updatedObject?.content_image === null) {
|
||||
updatedObject["content_image"] = ""
|
||||
}
|
||||
|
||||
|
||||
updatedObject?.answers?.forEach((item: any) => {
|
||||
if (item?.id) {
|
||||
if(item?.content_image === null){
|
||||
item["content_image"] = ""
|
||||
if (item?.content_image === null) {
|
||||
item["content_image"] = ""
|
||||
|
||||
}
|
||||
oldAnswers.push({ ...item, isCorrect: item?.isCorrect ? 1 : 0 });
|
||||
|
|
@ -121,20 +111,20 @@ const EditPage: React.FC = () => {
|
|||
old: oldAnswers,
|
||||
new: newAnswers,
|
||||
};
|
||||
const emptyTag = tags?.new?.length === 0 && tags?.old?.length === 0
|
||||
const tagToSend = emptyTag ? "" : tags
|
||||
const emptyTag = tags?.new?.length === 0 && tags?.old?.length === 0
|
||||
const tagToSend = emptyTag ? "" : tags
|
||||
mutate({
|
||||
...updatedObject,
|
||||
answers,
|
||||
tags:tagToSend,
|
||||
tags: tagToSend,
|
||||
});
|
||||
} else {
|
||||
console.log(values?.id);
|
||||
|
||||
const tags = processTags(item);
|
||||
console.log(item,"DataToSend");
|
||||
|
||||
console.log(tags,"tags");
|
||||
console.log(item, "DataToSend");
|
||||
|
||||
console.log(tags, "tags");
|
||||
mutateAdd({
|
||||
...item,
|
||||
subject_id: subject_id,
|
||||
|
|
@ -158,15 +148,15 @@ const EditPage: React.FC = () => {
|
|||
const newAnswers = [] as any;
|
||||
updatedObject?.answers?.forEach((item: any) => {
|
||||
if (item?.id) {
|
||||
console.log(item,"item");
|
||||
const deletedImage = item?.content_image === null
|
||||
if(deletedImage){
|
||||
oldAnswers.push({ ...item, isCorrect: item?.isCorrect ? 1 : 0, content_image:"" });
|
||||
console.log(item, "item");
|
||||
const deletedImage = item?.content_image === null
|
||||
if (deletedImage) {
|
||||
oldAnswers.push({ ...item, isCorrect: item?.isCorrect ? 1 : 0, content_image: "" });
|
||||
|
||||
}else{
|
||||
oldAnswers.push({ ...item, isCorrect: item?.isCorrect ? 1 : 0 });
|
||||
} else {
|
||||
oldAnswers.push({ ...item, isCorrect: item?.isCorrect ? 1 : 0 });
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
newAnswers.push({ ...item, isCorrect: item?.isCorrect ? 1 : 0 });
|
||||
}
|
||||
|
|
@ -187,113 +177,105 @@ const EditPage: React.FC = () => {
|
|||
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const handleCancel = () => {
|
||||
navigate(-1);
|
||||
};
|
||||
|
||||
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){
|
||||
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;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!haveOneAnswerRight) {
|
||||
toast.error(t("validation.it_should_have_more_than_one_correct_answers"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(haveImageOrContent){
|
||||
if (haveImageOrContent) {
|
||||
toast.error(t("validation.one_of_image_and_content_should_be_enter_in_answer"))
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
});
|
||||
console.log(1);
|
||||
|
||||
console.log(1);
|
||||
|
||||
if(isValid && isValidate){
|
||||
console.log(2);
|
||||
handleSubmit(values)
|
||||
}
|
||||
|
||||
};
|
||||
if (isValid) {
|
||||
handleSubmit(values)
|
||||
}
|
||||
|
||||
const handleNavigateToPage = () => {
|
||||
const cleanedUrl = location.pathname.replace(/\/Question\/\d+$/, "");
|
||||
navigate(cleanedUrl);
|
||||
};
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (isSuccess) {
|
||||
|
|
@ -302,31 +284,6 @@ const handleNavigateToPage = () => {
|
|||
}
|
||||
}, [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) {
|
||||
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 }) => (
|
||||
|
||||
<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>
|
||||
<BaseFormContainer t={t} Loading={Loading} handleSubmit={handleSubmit} handleValidateBaseQuestion={handleValidateBaseQuestion} objectToEdit={objectToEdit} />
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
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"
|
||||
onClick={()=>{ Loading ? ()=>{} : handleValidateSingleQuestion(values,isValid,handleSubmit) }}
|
||||
> {t("practical.edit")}
|
||||
{Loading && (
|
||||
<span className="Spinier_Div">
|
||||
<Spin />
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<FormContainer t={t} Loading={Loading} handleSubmit={handleSubmit} handleValidateSingleQuestion={handleValidateSingleQuestion} objectToEdit={objectToEdit} />
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
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;
|
||||
values:any
|
||||
}) => {
|
||||
console.log(567)
|
||||
const [t] = useTranslation();
|
||||
const { ShowHint } = useObjectToEdit();
|
||||
const handleDeleteChoice = () => {
|
||||
|
|
@ -120,7 +119,6 @@ const ChoiceFields = React.memo(
|
|||
}
|
||||
, (prevProps, nextProps) => {
|
||||
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];
|
||||
});
|
||||
|
|
|
|||
|
|
@ -113,8 +113,6 @@ const Choices = React.memo( ({setFieldValue ,values,parent_index }:any) => {
|
|||
</>
|
||||
);
|
||||
}, (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;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import { CombinationKeyEnum } from "../../../../../enums/CombinationKeyEnum";
|
|||
import { toast } from "react-toastify";
|
||||
import MainInputs from "./components/MainInputs";
|
||||
import Questions from "./components/Questions";
|
||||
import useUnsavedChangesWarning from "../../../../../Hooks/useUnsavedChangesWarning";
|
||||
|
||||
const Form = () => {
|
||||
const formik = useFormikContext<any>();
|
||||
|
|
@ -64,6 +65,8 @@ const Form = () => {
|
|||
|
||||
|
||||
const lastQuestions = formik?.values?.Questions?.length - 1;
|
||||
|
||||
////////////// hooks
|
||||
useKeyCombination(
|
||||
{ ctrlKey: true, shiftKey: true, code: CombinationKeyEnum.CHOICE },
|
||||
() => {
|
||||
|
|
@ -77,8 +80,10 @@ const lastQuestions = formik?.values?.Questions?.length - 1;
|
|||
handleAddQuestion(true);
|
||||
},
|
||||
);
|
||||
useUnsavedChangesWarning(formik.dirty);
|
||||
|
||||
|
||||
//////////////
|
||||
useEffect(() => {
|
||||
if (Success) {
|
||||
formik.resetForm()
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { CombinationKeyEnum } from "../../../../enums/CombinationKeyEnum";
|
|||
import { toast } from "react-toastify";
|
||||
import LaTeXInputMemo from "../../../../Components/LatextInput/LaTeXInputMemo";
|
||||
import ImageBoxFieldMemo from "../../../../Components/CustomFields/ImageBoxField/ImageBoxFieldMemo";
|
||||
import useUnsavedChangesWarning from "../../../../Hooks/useUnsavedChangesWarning";
|
||||
|
||||
const Form = () => {
|
||||
const [t] = useTranslation();
|
||||
|
|
@ -33,6 +34,10 @@ const Form = () => {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
////////////// hooks
|
||||
|
||||
|
||||
useKeyCombination(
|
||||
{ ctrlKey: true, shiftKey: true, code: CombinationKeyEnum.CHOICE },
|
||||
() => {
|
||||
|
|
@ -40,14 +45,16 @@ const Form = () => {
|
|||
},
|
||||
);
|
||||
|
||||
useUnsavedChangesWarning(formik.dirty);
|
||||
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (Success) {
|
||||
formik.resetForm()
|
||||
setSuccess(false);
|
||||
}
|
||||
}, [Success]);
|
||||
|
||||
console.log(formik.errors);
|
||||
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -6,9 +6,7 @@ const Dummy = () => {
|
|||
const [t] = useTranslation();
|
||||
return (
|
||||
<div className="DummyHomePage">
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ const LaTeXInputMemo: React.FC<any> = React.memo(({ field ,form, label, ...prop
|
|||
const { setFieldValue } = form;
|
||||
const [curCentValue, setCurrentValue] = useState(value)
|
||||
const handleChangeInput = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||
setFieldValue(name, e.target.value);
|
||||
// setFieldValue(name, e.target.value);
|
||||
setCurrentValue(e.target.value)
|
||||
};
|
||||
console.log(name,"name");
|
||||
|
|
@ -24,6 +24,7 @@ const LaTeXInputMemo: React.FC<any> = React.memo(({ field ,form, label, ...prop
|
|||
</label>
|
||||
|
||||
<div className='LaTeXInputArea'>
|
||||
|
||||
<TextArea
|
||||
size="large"
|
||||
showCount
|
||||
|
|
|
|||
|
|
@ -114,4 +114,7 @@ svg{
|
|||
|
||||
.LaTeXRenderer{
|
||||
direction: ltr;
|
||||
}
|
||||
.ant-input,.LaTeXInputArea,input{
|
||||
|
||||
}
|
||||
|
|
@ -100,4 +100,9 @@
|
|||
.transparent_bg{
|
||||
background: transparent !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.disabled{
|
||||
pointer-events: none;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
|
@ -52,7 +52,8 @@
|
|||
"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_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": {
|
||||
"register_students": "تسجيل الطلاب",
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user