add check on reload

This commit is contained in:
karimaldeen 2024-09-22 11:09:15 +03:00
parent ec4850cbb8
commit 470cae3b13
21 changed files with 770 additions and 493 deletions

View File

@ -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 = ()=>{
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>
<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 fallback={<SpinContainer />}>
</Suspense>
</div>
);

View 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;

View File

@ -36,7 +36,6 @@ const DynamicTags = () => {
if (currentElement) {
currentElement.focus(); // Set focus on the element
}
console.log(currentElement,"currentElement");
}, [lastElementIndex])
// console.log(formik?.values);

View File

@ -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}>

View File

@ -1,35 +1,23 @@
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 { 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) => {
@ -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;
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} />
);
};

View File

@ -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,16 +14,11 @@ 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>();
@ -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 });
@ -187,9 +177,6 @@ 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;
@ -288,11 +275,6 @@ if(isValid && isValidate){
handleSubmit(values)
}
};
const handleNavigateToPage = () => {
const cleanedUrl = location.pathname.replace(/\/Question\/\d+$/, "");
navigate(cleanedUrl);
};
useEffect(() => {
@ -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} />
);
};

View 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

View 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

View 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)
}
};

View 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

View 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

View 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)
}
};

View File

@ -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];
});

View File

@ -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;
});

View File

@ -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()

View File

@ -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,6 +45,10 @@ const Form = () => {
},
);
useUnsavedChangesWarning(formik.dirty);
useEffect(() => {
if (Success) {
formik.resetForm()
@ -47,8 +56,6 @@ const Form = () => {
}
}, [Success]);
console.log(formik.errors);
return (
<Row className="w-100 exercise_form_container">

View File

@ -7,8 +7,6 @@ const Dummy = () => {
return (
<div className="DummyHomePage">
</div>
);
};

View File

@ -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

View File

@ -115,3 +115,6 @@ svg{
.LaTeXRenderer{
direction: ltr;
}
.ant-input,.LaTeXInputArea,input{
}

View File

@ -101,3 +101,8 @@
background: transparent !important;
color: #fff !important;
}
.disabled{
pointer-events: none;
opacity: 0.6;
}

View File

@ -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": "تسجيل الطلاب",