Compare commits
6 Commits
36feda0b43
...
fc861e768f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc861e768f | ||
|
|
5c41a13cb1 | ||
|
|
cd89ad405b | ||
|
|
dbdaa04fde | ||
|
|
a8967b62f2 | ||
|
|
0586a88cab |
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
|
|
@ -10,6 +10,7 @@
|
|||
"Groupbutton",
|
||||
"handelnavigate",
|
||||
"Karim",
|
||||
"Popconfirm",
|
||||
"queryqlent",
|
||||
"registraion",
|
||||
"SENDNOTIFICATION",
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ const ImageBoxField = ({ name }: any) => {
|
|||
</div>
|
||||
<div className="ImageBox">
|
||||
{imagePreview ? (
|
||||
<img src={imagePreview} alt="Preview" className="imagePreview" />
|
||||
<img src={imagePreview} onClick={handleButtonClick} alt="Preview" className="imagePreview" />
|
||||
) : (
|
||||
<ImageIcon onClick={handleButtonClick} className="ImageBoxIcon" />
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -14,10 +14,10 @@ const TextField = ({
|
|||
placeholder,
|
||||
isDisabled,
|
||||
onChange,
|
||||
props,
|
||||
no_label,
|
||||
label_icon,
|
||||
className,
|
||||
...props
|
||||
}: any) => {
|
||||
const { formik, isError, errorMsg, t } = useFormField(name, props);
|
||||
const TextFilehandleChange = (
|
||||
|
|
@ -48,6 +48,7 @@ const TextField = ({
|
|||
onChange={onChange || TextFilehandleChange}
|
||||
style={{ height: 120 }}
|
||||
id={name}
|
||||
{...props}
|
||||
/>
|
||||
</ValidationFieldContainer>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,14 +4,16 @@ import { useTranslation } from "react-i18next";
|
|||
import { GoArrowSwitch } from "react-icons/go";
|
||||
import { useObjectToEdit } from "../../zustand/ObjectToEditState";
|
||||
import { QUESTION_OBJECT_KEY } from "../../config/AppKey";
|
||||
import { Popover } from "antd";
|
||||
import { Popconfirm, Popover } from "antd";
|
||||
import { CombinationKeyEnum } from "../../enums/CombinationKeyEnum";
|
||||
import { PopconfirmProps } from "antd/lib";
|
||||
|
||||
const Header = () => {
|
||||
const [t] = useTranslation();
|
||||
const { values, setFieldValue, setValues } = useFormikContext<any>();
|
||||
const { isBseQuestion, setIsBseQuestion } = useObjectToEdit();
|
||||
const { setSavedQuestionData } = useObjectToEdit();
|
||||
|
||||
const handleChange = () => {
|
||||
setSavedQuestionData(null);
|
||||
localStorage.removeItem(QUESTION_OBJECT_KEY);
|
||||
|
|
@ -26,6 +28,14 @@ const Header = () => {
|
|||
}
|
||||
};
|
||||
|
||||
const confirm: PopconfirmProps['onConfirm'] = (e) => {
|
||||
console.log(e);
|
||||
setTimeout(() => {
|
||||
handleChange()
|
||||
}, 500);
|
||||
|
||||
};
|
||||
|
||||
const content = (
|
||||
<div>
|
||||
<p>
|
||||
|
|
@ -52,7 +62,18 @@ const Header = () => {
|
|||
</div>
|
||||
</article>
|
||||
<div>
|
||||
<GoArrowSwitch onClick={handleChange} className="m-2" />
|
||||
<Popconfirm
|
||||
title={t("header.this_will_un_do_all_your_changes")}
|
||||
okText={t("practical.yes")}
|
||||
cancelText={t("practical.no")}
|
||||
onConfirm={()=>{confirm()}}
|
||||
defaultOpen={false}
|
||||
|
||||
>
|
||||
|
||||
<GoArrowSwitch className="m-2" />
|
||||
|
||||
</Popconfirm>
|
||||
{isBseQuestion || values?.isBase === 1
|
||||
? t("header.malty_exercise")
|
||||
: t("header.exercise")}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { useEffect } from "react";
|
|||
|
||||
const useFormField = (name: string, props?: any) => {
|
||||
const [field, meta] = useField({ name, ...props });
|
||||
|
||||
const { t } = useTranslation();
|
||||
const formik = useFormikContext<any>();
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ const FormikFormModel: React.FC<FormikFormProps> = ({
|
|||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={handleSubmit}
|
||||
|
||||
>
|
||||
{(formik) => {
|
||||
useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import {
|
|||
} from "./Model/formUtil";
|
||||
import { useAddQuestion, useAddQuestionAsync } from "../../../api/Question";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { useLocation, useNavigate, useParams } from "react-router-dom";
|
||||
import { ParamsEnum } from "../../../enums/params";
|
||||
import { useObjectToEdit } from "../../../zustand/ObjectToEditState";
|
||||
|
||||
|
|
@ -19,9 +19,13 @@ 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";
|
||||
const AcceptModal = lazy(() => import("./Model/AcceptModal"));
|
||||
|
||||
const AddPage: React.FC = () => {
|
||||
const location = useLocation();
|
||||
|
||||
const { mutateAsync,isLoading:LoadingAsync } = useAddQuestionAsync();
|
||||
const { mutate, isLoading, isSuccess } = useAddQuestion();
|
||||
const { isBseQuestion, setTagsSearch, objectToEdit, setSuccess } =
|
||||
|
|
@ -30,12 +34,7 @@ const AddPage: React.FC = () => {
|
|||
const [t] = useTranslation();
|
||||
const { subject_id, lesson_id } = useParams<ParamsEnum>();
|
||||
|
||||
console.log(objectToEdit, "objectToEdit");
|
||||
|
||||
const handleSubmit = (
|
||||
values: any,
|
||||
{ resetForm }: { resetForm: () => void },
|
||||
) => {
|
||||
const handleSubmit = ( values: any) => {
|
||||
const DataToSend = structuredClone(values);
|
||||
setTagsSearch(null);
|
||||
console.log(1);
|
||||
|
|
@ -95,17 +94,6 @@ const AddPage: React.FC = () => {
|
|||
};
|
||||
});
|
||||
|
||||
if (answers?.length > 0) {
|
||||
const isValidAnswers = answers?.some(
|
||||
(answer: any) => answer?.isCorrect === 1,
|
||||
);
|
||||
console.log(!isValidAnswers);
|
||||
|
||||
if (!isValidAnswers) {
|
||||
toast.error(t("validation.at_least_one_answer_should_be_correct"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const NewQuestion = {
|
||||
...values,
|
||||
|
|
@ -122,14 +110,65 @@ const AddPage: React.FC = () => {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
const handleValidateSingleQuestion = (values:any)=>{
|
||||
const haveAnswers = values?.answers?.length > 0 ;
|
||||
const haveMoreThanOneAnswer = haveAnswers && values?.answers?.length > 1;
|
||||
const haveOneAnswerRight = haveMoreThanOneAnswer && values?.answers?.some((item:any)=> item?.isCorrect === 1 || item.isCorrect === true )
|
||||
if(!haveAnswers){
|
||||
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 ;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const handleValidateBaseQuestion = (values: any) => {
|
||||
const haveAnswers = values?.Questions?.every((Question: any, QuestionsIndex: number) => {
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
console.log(haveAnswers, "haveAnswers");
|
||||
};
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleNavigateToPage = () => {
|
||||
const cleanedUrl = location.pathname?.replace("/Question/add", "");
|
||||
navigate(cleanedUrl);
|
||||
};
|
||||
const handleCancel = () => {
|
||||
navigate(-1);
|
||||
};
|
||||
const Loading = LoadingAsync || isLoading
|
||||
useEffect(() => {
|
||||
console.log("all api success");
|
||||
if (isSuccess) {
|
||||
setSuccess(true);
|
||||
}
|
||||
|
|
@ -137,19 +176,32 @@ const AddPage: React.FC = () => {
|
|||
|
||||
if (isBseQuestion) {
|
||||
return (
|
||||
|
||||
<div className="QuestionPractical">
|
||||
<header>
|
||||
<MdOutlineArrowForwardIos onClick={handleNavigateToPage} /> {t("header.add_new_question")}
|
||||
</header>
|
||||
|
||||
<div className="exercise_add">
|
||||
<FormikForm
|
||||
handleSubmit={handleSubmit}
|
||||
initialValues={getInitialValuesBase(objectToEdit)}
|
||||
validationSchema={getValidationSchemaBase}
|
||||
<Formik
|
||||
onSubmit={handleSubmit}
|
||||
initialValues={getInitialValuesBase({} as any)}
|
||||
validationSchema={getValidationSchemaBase}
|
||||
enableReinitialize
|
||||
>
|
||||
{({ values,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="submit">
|
||||
<button disabled={Loading} className="relative" type="submit"
|
||||
onClick={()=>{handleValidateBaseQuestion(values) ;handleSubmit(values)}}
|
||||
onSubmit={()=>{handleValidateBaseQuestion(values) ;handleSubmit(values) }}
|
||||
>
|
||||
{t("practical.add")}
|
||||
|
||||
{Loading && (
|
||||
|
|
@ -160,42 +212,67 @@ const AddPage: React.FC = () => {
|
|||
</button>
|
||||
</div>
|
||||
</main>
|
||||
</FormikForm>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
<Suspense fallback={<Spin />}>
|
||||
<AcceptModal />
|
||||
</Suspense>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="exercise_add">
|
||||
<FormikForm
|
||||
handleSubmit={handleSubmit}
|
||||
initialValues={getInitialValues(objectToEdit)}
|
||||
validationSchema={getValidationSchema}
|
||||
>
|
||||
<main className="w-100 exercise_add_main">
|
||||
<Header />
|
||||
<ModelForm />
|
||||
|
||||
<div className="exercise_add_buttons">
|
||||
<div onClick={handleCancel}>{t("practical.back")}</div>
|
||||
<button disabled={Loading} className="relative" type="submit">
|
||||
{t("practical.add")}
|
||||
<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}
|
||||
onSubmit={(values) => {
|
||||
handleSubmit(values);
|
||||
}}
|
||||
>
|
||||
{({ values,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>
|
||||
<button
|
||||
disabled={Loading}
|
||||
className="relative"
|
||||
onClick={()=>{handleValidateSingleQuestion(values) ;handleSubmit(values)}}
|
||||
onSubmit={()=>{handleValidateSingleQuestion(values) ;handleSubmit(values) }}
|
||||
type="submit"
|
||||
>
|
||||
{t("practical.add")}
|
||||
|
||||
{Loading && (
|
||||
<span className="Spinier_Div">
|
||||
<Spin />
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</main>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
|
||||
{Loading && (
|
||||
<span className="Spinier_Div">
|
||||
<Spin />
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</main>
|
||||
</FormikForm>
|
||||
<Suspense fallback={<Spin />}>
|
||||
<AcceptModal />
|
||||
</Suspense>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ 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";
|
||||
|
||||
const EditPage: React.FC = () => {
|
||||
const { subject_id, lesson_id, question_id } = useParams<ParamsEnum>();
|
||||
|
|
@ -187,6 +189,59 @@ const EditPage: React.FC = () => {
|
|||
};
|
||||
|
||||
|
||||
const handleValidateSingleQuestion = (values:any)=>{
|
||||
const haveAnswers = values?.answers?.length > 0 ;
|
||||
const haveMoreThanOneAnswer = haveAnswers && values?.answers?.length > 1;
|
||||
const haveOneAnswerRight = haveMoreThanOneAnswer && values?.answers?.some((item:any)=> item?.isCorrect === 1 || item.isCorrect === true )
|
||||
if(!haveAnswers){
|
||||
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 ;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const handleValidateBaseQuestion = (values: any) => {
|
||||
const haveAnswers = values?.Questions?.every((Question: any, QuestionsIndex: number) => {
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
console.log(haveAnswers, "haveAnswers");
|
||||
};
|
||||
|
||||
|
||||
const handleNavigateToPage = () => {
|
||||
const cleanedUrl = location.pathname.replace(/\/Question\/\d+$/, "");
|
||||
navigate(cleanedUrl);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (isSuccess) {
|
||||
toast.success(t("validation.the_possess_done_successful"));
|
||||
|
|
@ -201,13 +256,24 @@ const EditPage: React.FC = () => {
|
|||
}
|
||||
if (objectToEdit?.isBase) {
|
||||
return (
|
||||
|
||||
|
||||
<div className="QuestionPractical">
|
||||
<header>
|
||||
<MdOutlineArrowForwardIos onClick={handleNavigateToPage} /> {t("header.edit_question")}
|
||||
</header>
|
||||
|
||||
<div className="exercise_add">
|
||||
<FormikForm
|
||||
handleSubmit={handleSubmit}
|
||||
initialValues={getInitialValuesBase(objectToEdit)}
|
||||
validationSchema={getValidationSchemaBase}
|
||||
<Formik
|
||||
onSubmit={handleSubmit}
|
||||
initialValues={getInitialValuesBase(objectToEdit)}
|
||||
validationSchema={getValidationSchemaBase}
|
||||
enableReinitialize
|
||||
>
|
||||
<main className="w-100 exercise_add_main">
|
||||
{({ values,handleSubmit }) => (
|
||||
|
||||
<Form className="w-100">
|
||||
<main className="w-100 exercise_add_main">
|
||||
{/* <Header/> */}
|
||||
<header className="exercise_add_header mb-4">
|
||||
<div>
|
||||
|
|
@ -218,8 +284,10 @@ const EditPage: React.FC = () => {
|
|||
<BaseForm />
|
||||
<div className="exercise_add_buttons">
|
||||
<div onClick={handleCancel}>{t("practical.back")}</div>
|
||||
<button disabled={Loading} className="relative" type="submit">
|
||||
{t("practical.edit")}
|
||||
<button disabled={Loading} className="relative" type="submit"
|
||||
onClick={()=>{handleValidateBaseQuestion(values) ;handleSubmit(values)}}
|
||||
onSubmit={()=>{handleValidateBaseQuestion(values) ;handleSubmit(values) }}
|
||||
> {t("practical.edit")}
|
||||
|
||||
{Loading && (
|
||||
<span className="Spinier_Div">
|
||||
|
|
@ -229,19 +297,35 @@ const EditPage: React.FC = () => {
|
|||
</button>
|
||||
</div>
|
||||
</main>
|
||||
</FormikForm>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
|
||||
<div className="QuestionPractical">
|
||||
<header>
|
||||
<MdOutlineArrowForwardIos onClick={handleNavigateToPage} /> {t("header.edit_question")}
|
||||
</header>
|
||||
<div className="exercise_add">
|
||||
<FormikForm
|
||||
handleSubmit={handleSubmit}
|
||||
initialValues={getInitialValues(objectToEdit)}
|
||||
validationSchema={getValidationSchema}
|
||||
>
|
||||
<main className="w-100 exercise_add_main">
|
||||
|
||||
<Formik
|
||||
enableReinitialize={true}
|
||||
initialValues={getInitialValues(objectToEdit)}
|
||||
validationSchema={getValidationSchema}
|
||||
onSubmit={(values) => {
|
||||
handleSubmit(values);
|
||||
}}
|
||||
>
|
||||
{({ values,handleSubmit }) => (
|
||||
<Form className="w-100">
|
||||
<main className="w-100 exercise_add_main">
|
||||
{/* <Header/> */}
|
||||
<header className="exercise_add_header mb-4">
|
||||
<div>
|
||||
|
|
@ -252,8 +336,13 @@ const EditPage: React.FC = () => {
|
|||
<ModelForm />
|
||||
<div className="exercise_add_buttons">
|
||||
<div onClick={handleCancel}>{t("practical.back")}</div>
|
||||
<button disabled={Loading} className="relative" type="submit">
|
||||
{t("practical.edit")}
|
||||
<button
|
||||
disabled={Loading}
|
||||
className="relative"
|
||||
onClick={()=>{handleValidateSingleQuestion(values) ;handleSubmit(values)}}
|
||||
onSubmit={()=>{handleValidateSingleQuestion(values) ;handleSubmit(values) }}
|
||||
type="submit"
|
||||
> {t("practical.edit")}
|
||||
|
||||
{Loading && (
|
||||
<span className="Spinier_Div">
|
||||
|
|
@ -263,8 +352,14 @@ const EditPage: React.FC = () => {
|
|||
</button>
|
||||
</div>
|
||||
</main>
|
||||
</FormikForm>
|
||||
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ const ChoiceFields = ({ index, data }: { index: number; data: Choice }) => {
|
|||
name={index}
|
||||
id={`choice_${index + 1}`}
|
||||
type="TextArea"
|
||||
|
||||
/>
|
||||
|
||||
<ImageBoxField name={`answers.${index}.content_image`} />
|
||||
|
|
@ -50,11 +51,11 @@ const ChoiceFields = ({ index, data }: { index: number; data: Choice }) => {
|
|||
name={index}
|
||||
type="Checkbox"
|
||||
/>
|
||||
<p className="delete_question_options">
|
||||
<p className="delete_question_options" onClick={handleDeleteChoice}>
|
||||
{t("header.delete_choice")}
|
||||
<GoTrash
|
||||
className="trash_icon"
|
||||
onClick={handleDeleteChoice}
|
||||
|
||||
size={17}
|
||||
/>
|
||||
</p>
|
||||
|
|
@ -66,8 +67,9 @@ const ChoiceFields = ({ index, data }: { index: number; data: Choice }) => {
|
|||
placeholder="_"
|
||||
name={`answers.${index}.hint`}
|
||||
label="hint"
|
||||
type="text"
|
||||
style={{ width: "100%" }}
|
||||
type="TextArea"
|
||||
style={{ width: "100%" , height: 60,resize:"none" }}
|
||||
showCount={false}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -36,12 +36,21 @@ const Choices = () => {
|
|||
};
|
||||
|
||||
return (
|
||||
<DragDropContext onDragEnd={handleDragEnd}>
|
||||
<>
|
||||
{formik?.values?.answers?.map((item: Choice, index: number) => {
|
||||
return (
|
||||
<div
|
||||
>
|
||||
<ChoiceFields index={index} data={item} />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
{/* <DragDropContext onDragEnd={handleDragEnd}>
|
||||
<Droppable droppableId="choices">
|
||||
{(provided) => (
|
||||
<div {...provided.droppableProps} ref={provided.innerRef}>
|
||||
{formik?.values?.answers?.map((item: Choice, index: number) => {
|
||||
// Use a unique identifier for draggableId
|
||||
const draggableId = item.name
|
||||
? item.name.toString()
|
||||
: `item-${index}`;
|
||||
|
|
@ -67,11 +76,12 @@ const Choices = () => {
|
|||
</Draggable>
|
||||
);
|
||||
})}
|
||||
{provided.placeholder} {/* Placeholder for spacing */}
|
||||
{provided.placeholder}
|
||||
</div>
|
||||
)}
|
||||
</Droppable>
|
||||
</DragDropContext>
|
||||
</DragDropContext> */}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -72,11 +72,11 @@ const ChoiceFields = ({
|
|||
type="Checkbox"
|
||||
parent_index={parent_index}
|
||||
/>
|
||||
<p className="delete_question_options">
|
||||
<p className="delete_question_options" onClick={handleDeleteChoice}>
|
||||
{t("header.delete_choice")}
|
||||
<GoTrash
|
||||
className="trash_icon"
|
||||
onClick={handleDeleteChoice}
|
||||
|
||||
size={17}
|
||||
/>
|
||||
</p>
|
||||
|
|
@ -89,8 +89,9 @@ const ChoiceFields = ({
|
|||
placeholder="_"
|
||||
name={`Questions.${parent_index}.answers.${index}.hint`}
|
||||
label="hint"
|
||||
type="text"
|
||||
style={{ width: "100%" }}
|
||||
type="TextArea"
|
||||
style={{ width: "100%" , height: 60,resize:"none" }}
|
||||
showCount={false}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -44,7 +44,28 @@ const Choices = ({ parent_index }: { parent_index: number }) => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<DragDropContext onDragEnd={handleDragEnd}>
|
||||
|
||||
<div>
|
||||
{(
|
||||
(formik?.values as any)?.Questions?.[parent_index]?.answers ||
|
||||
[]
|
||||
).map((item: Choice, index: number) => {
|
||||
return (
|
||||
<div
|
||||
|
||||
>
|
||||
<ChoiceFields
|
||||
key={index}
|
||||
parent_index={parent_index}
|
||||
index={index}
|
||||
data={item}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
</div>
|
||||
{/* <DragDropContext onDragEnd={handleDragEnd}>
|
||||
<Droppable droppableId="choices">
|
||||
{(provided) => (
|
||||
<div {...provided.droppableProps} ref={provided.innerRef}>
|
||||
|
|
@ -87,7 +108,7 @@ const Choices = ({ parent_index }: { parent_index: number }) => {
|
|||
</div>
|
||||
)}
|
||||
</Droppable>
|
||||
</DragDropContext>
|
||||
</DragDropContext> */}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -86,6 +86,8 @@ const Form = () => {
|
|||
},
|
||||
);
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<Row className="w-100 exercise_form_container">
|
||||
<div className="exercise_form">
|
||||
|
|
@ -99,7 +101,7 @@ const Form = () => {
|
|||
|
||||
<div></div>
|
||||
</div>
|
||||
<div className=" flex "></div>
|
||||
<div className="flex"></div>
|
||||
|
||||
{((formik?.values as any)?.Questions || [])?.map(
|
||||
(item: Choice, parent_index: number) => {
|
||||
|
|
@ -132,8 +134,9 @@ const Form = () => {
|
|||
placeholder="_"
|
||||
name={`Questions.${parent_index}.hint`}
|
||||
label="hint_question"
|
||||
type="text"
|
||||
style={{ width: "100%" }}
|
||||
type="TextArea"
|
||||
style={{ width: "100%" , height: 60,resize:"none" }}
|
||||
showCount={false}
|
||||
/>
|
||||
<MaltySelectTag parent_index={parent_index} />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -53,12 +53,12 @@ const QuestionFIeld = ({ index, data }: { index: number; data: Choice }) => {
|
|||
|
||||
<ImageBoxField name={`Questions.${index}.content_image`} />
|
||||
|
||||
<div className="answer_status">
|
||||
<div className="answer_status" onClick={handleDeleteQuestion}>
|
||||
<p className="delete_question_options">
|
||||
{t("header.delete_question")}
|
||||
<GoTrash
|
||||
className="trash_icon"
|
||||
onClick={handleDeleteQuestion}
|
||||
|
||||
size={17}
|
||||
/>
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -41,14 +41,10 @@ const MaltySelectTag = ({ parent_index }: { parent_index: number }) => {
|
|||
? [{ id: searchValue, name: searchValue }]
|
||||
: [];
|
||||
|
||||
console.log(options);
|
||||
const value =
|
||||
formik?.values?.Questions[parent_index]?.tags?.map(
|
||||
(item: any) => item?.id ?? item,
|
||||
) ?? [];
|
||||
console.log(formik?.values?.Questions[parent_index]);
|
||||
|
||||
console.log(value);
|
||||
|
||||
const AllOptions = [...options, ...additionalData];
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ const Form = () => {
|
|||
|
||||
const handleAddChoice = (fromKeyCombination: boolean = false) => {
|
||||
formik.setFieldValue("answers", [
|
||||
...((formik?.values as any)?.answers as Choice[]),
|
||||
...(formik?.values?.answers ?? []) ,
|
||||
{
|
||||
content: null,
|
||||
content_image: null,
|
||||
|
|
@ -42,13 +42,12 @@ const Form = () => {
|
|||
|
||||
useEffect(() => {
|
||||
if (Success) {
|
||||
formik?.setValues({});
|
||||
formik.setErrors({});
|
||||
formik.resetForm()
|
||||
setSuccess(false);
|
||||
console.log(formik.errors);
|
||||
}
|
||||
}, [Success]);
|
||||
|
||||
|
||||
return (
|
||||
<Row className="w-100 exercise_form_container">
|
||||
<div className="exercise_form">
|
||||
|
|
@ -62,7 +61,7 @@ const Form = () => {
|
|||
</div>
|
||||
|
||||
<Choices />
|
||||
{formik?.values?.answers?.length < 5 && (
|
||||
{(formik?.values?.answers === null || formik?.values?.answers === undefined || formik?.values?.answers?.length < 5) && (
|
||||
<p className="add_new_button">
|
||||
<FaCirclePlus onClick={() => handleAddChoice()} size={23} />{" "}
|
||||
{t("header.add_new_choice")}
|
||||
|
|
@ -75,8 +74,10 @@ const Form = () => {
|
|||
placeholder="_"
|
||||
name="hint"
|
||||
label="hint_question"
|
||||
type="text"
|
||||
style={{ width: "100%" }}
|
||||
type="TextArea"
|
||||
style={{ width: "100%" , height: 60,resize:"none" }}
|
||||
showCount={false}
|
||||
|
||||
/>
|
||||
<SelectTag />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ export const getInitialValues = (objectToEdit: Question): any => {
|
|||
hint: objectToEdit?.hint ?? null,
|
||||
isBase: 0,
|
||||
parent_id: objectToEdit?.parent_id ?? "",
|
||||
answers: objectToEdit?.answers ?? [],
|
||||
answers: objectToEdit?.answers ?? null,
|
||||
tags: tags ?? [],
|
||||
};
|
||||
};
|
||||
|
|
@ -32,6 +32,19 @@ export const getValidationSchema = () => {
|
|||
content_image: Yup.string().nullable(),
|
||||
isCorrect: Yup.boolean(),
|
||||
}),
|
||||
).min(2).test(
|
||||
"at-least-one-correct",
|
||||
"At least one answer must be correct",
|
||||
(answers: any) => {
|
||||
console.log(answers, "answers");
|
||||
if(answers === null){
|
||||
return true
|
||||
}
|
||||
return answers?.some(
|
||||
(answer: any) =>
|
||||
answer?.isCorrect === true || answer?.isCorrect === 1,
|
||||
);
|
||||
},
|
||||
),
|
||||
});
|
||||
};
|
||||
|
|
@ -42,10 +55,18 @@ export const getInitialValuesBase = (objectToEdit: Question): any => {
|
|||
id: tag?.id,
|
||||
name: tag?.name,
|
||||
}));
|
||||
console.log(item, "item");
|
||||
const newAnswers = item?.answers?.map((item:any)=>{
|
||||
return {
|
||||
...item,
|
||||
content : item?.content ?? null
|
||||
|
||||
}
|
||||
})
|
||||
console.log(newAnswers,"newAnswers");
|
||||
|
||||
return {
|
||||
...item,
|
||||
answer:newAnswers,
|
||||
canAnswersBeShuffled: objectToEdit?.canAnswersBeShuffled ? 1 : 0,
|
||||
hint: objectToEdit?.hint ?? "",
|
||||
isBase: 0,
|
||||
|
|
@ -53,7 +74,7 @@ export const getInitialValuesBase = (objectToEdit: Question): any => {
|
|||
};
|
||||
});
|
||||
|
||||
const questions = newQuestions ?? [];
|
||||
const questions = newQuestions ?? [{answers:[]}];
|
||||
|
||||
return {
|
||||
id: objectToEdit?.id ?? null,
|
||||
|
|
@ -84,12 +105,15 @@ export const getValidationSchemaBase = () => {
|
|||
answer_image: Yup.string().nullable(),
|
||||
isCorrect: Yup.boolean(),
|
||||
}),
|
||||
)
|
||||
).min(2)
|
||||
.test(
|
||||
"at-least-one-correct",
|
||||
"At least one answer must be correct",
|
||||
(answers: any) => {
|
||||
console.log(answers, "answers");
|
||||
|
||||
if(answers === null){
|
||||
return true
|
||||
}
|
||||
|
||||
return answers.some(
|
||||
(answer: any) =>
|
||||
|
|
@ -98,7 +122,7 @@ export const getValidationSchemaBase = () => {
|
|||
},
|
||||
),
|
||||
}),
|
||||
),
|
||||
).min(1),
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import DeleteModels from "../../../Layout/Dashboard/DeleteModels";
|
|||
import { ModalEnum } from "../../../enums/Model";
|
||||
import { useGetAllSubject } from "../../../api/subject";
|
||||
import { useGetAllGrade } from "../../../api/grade";
|
||||
import { useGetAllCurriculum } from "../../../api/curriculum";
|
||||
import PageHeader from "../../../Layout/Dashboard/PageHeader";
|
||||
import { ABILITIES_ENUM } from "../../../enums/abilities";
|
||||
import { canAddQuestion } from "../../../utils/hasAbilityFn";
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import {
|
|||
} from "../../config/AppKey";
|
||||
import useFormatAuthDataToSelect from "../../utils/useFormatAuthDataToSelect";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import ValidationField from "../../Components/ValidationField/ValidationField";
|
||||
|
||||
type FormFieldType = {
|
||||
isLoading: boolean;
|
||||
|
|
@ -25,22 +26,11 @@ const FormField = ({ isLoading }: FormFieldType) => {
|
|||
<Form className="AuthForm">
|
||||
{/* <Image style={{background:"#000"}} src="../App/Logo.png" /> */}
|
||||
<h2>{t("تسجيل الدخول إلى حسابك")}</h2>
|
||||
<div className="AuthInput">
|
||||
<label className="form-label" htmlFor="username">
|
||||
{t("input.Username")}
|
||||
</label>
|
||||
<Field
|
||||
placeholder={t("input.Username")}
|
||||
as={Input}
|
||||
type="text"
|
||||
id="username"
|
||||
name="username"
|
||||
className="Input"
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="AuthInput">
|
||||
<ValidationField name="username" label="username" />
|
||||
|
||||
<ValidationField name="password" label="password" />
|
||||
{/* <div className="AuthInput">
|
||||
<label className="form-label" htmlFor="password">
|
||||
{t("input.Password")}
|
||||
</label>
|
||||
|
|
@ -53,7 +43,7 @@ const FormField = ({ isLoading }: FormFieldType) => {
|
|||
className="passwordInput"
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
</div> */}
|
||||
|
||||
<button disabled={isLoading} type="submit" className="auth_submit_button">
|
||||
{t("practical.login")}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import useAuthState from "../../zustand/AuthState";
|
|||
import useNavigateOnSuccess from "../../Hooks/useNavigateOnSuccess";
|
||||
import { useLoginAdmin } from "../../api/auth";
|
||||
import FormField from "./FormField";
|
||||
import { initialValues } from "./formutils";
|
||||
import { initialValues, validationSchema } from "./formutils";
|
||||
import { FormValues } from "../../types/Auth";
|
||||
import { toast } from "react-toastify";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
|
@ -39,7 +39,7 @@ const LoginForm = () => {
|
|||
|
||||
return (
|
||||
<div className="LoginForm">
|
||||
<Formik initialValues={initialValues} onSubmit={handelSubmit}>
|
||||
<Formik initialValues={initialValues} onSubmit={handelSubmit} validationSchema={validationSchema} >
|
||||
{(formikProps) => <FormField isLoading={isLoading} />}
|
||||
</Formik>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import * as Yup from "yup";
|
|||
import { FormValues } from "../../types/Auth";
|
||||
|
||||
export const validationSchema = Yup.object().shape({
|
||||
username: Yup.string().required("Username is required"),
|
||||
password: Yup.string().required("Password is required"),
|
||||
username: Yup.string().required("validation.required"),
|
||||
password: Yup.string().required("validation.required").min(8,"validation.Password_must_be_at_least_8_characters_long"),
|
||||
});
|
||||
|
||||
export const initialValues: FormValues = {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { useTranslation } from "react-i18next";
|
|||
import { ABILITIES_ENUM } from "../../enums/abilities";
|
||||
import useSetPageTitle from "../../Hooks/useSetPageTitle";
|
||||
import useFilter from "../../Components/FilterField/components/useFilter";
|
||||
import { Button, Popconfirm } from "antd";
|
||||
|
||||
const Dummy = () => {
|
||||
const [t] = useTranslation();
|
||||
|
|
@ -12,6 +13,7 @@ const Dummy = () => {
|
|||
<div className="DummyHomePage">
|
||||
{/* <FilterButton />
|
||||
<FilterBody>karim</FilterBody> */}
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,12 +10,7 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.Popover {
|
||||
.ant-popover-inner {
|
||||
padding: 0 !important;
|
||||
}
|
||||
}
|
||||
x
|
||||
|
||||
.Color_type_checkbox.false {
|
||||
.ant-checkbox-checked .ant-checkbox-inner {
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@
|
|||
// padding: 2vw;
|
||||
.exercise_add_main {
|
||||
background: var(--bg);
|
||||
padding: 2vw;
|
||||
padding: 10px 2vw;
|
||||
}
|
||||
.exercise_add_buttons {
|
||||
display: flex;
|
||||
|
|
@ -144,7 +144,8 @@
|
|||
.delete_question_options {
|
||||
margin-top: 25px;
|
||||
color: var(--warning);
|
||||
|
||||
z-index: 9999;
|
||||
cursor: pointer;
|
||||
padding-left: 10px;
|
||||
.trash_icon {
|
||||
margin-right: 10px !important;
|
||||
|
|
@ -211,3 +212,37 @@
|
|||
transform: translateY(55px);
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.ant-popconfirm .ant-popconfirm-buttons{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
>{
|
||||
flex: 1;
|
||||
min-height: auto;
|
||||
min-width: 30px;
|
||||
|
||||
}
|
||||
.ant-btn{
|
||||
min-height: 30px !important;
|
||||
max-height: 30px !important;
|
||||
min-width: 50px;
|
||||
padding: 5px !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center ;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.QuestionPractical{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--bg);
|
||||
>header{
|
||||
padding: 30px 2vw 10px 2vw;
|
||||
}
|
||||
}
|
||||
|
|
@ -46,7 +46,9 @@
|
|||
"grade_to_pass_must_be_less_than_max_grade": "يجب أن تكون درجة النجاح أقل من الحد الأقصى للدرجة",
|
||||
"max_mark_must_be_greater_than_min_mark_to_pass": "يجب ان تكون اكبر من علامة النجاح",
|
||||
"Sorry, the question must have at least one option": "عذرًا، يجب أن يحتوي السؤال على خيار واحد على الأقل",
|
||||
"at_least_one_answer_should_be_correct": "يجب أن تكون إجابة واحدة صحيحة"
|
||||
"at_least_one_answer_should_be_correct": "يجب أن تكون إجابة واحدة صحيحة",
|
||||
"it_should_have_more_than_one_answers":"يجب أن يحتوي على أكثر من إجابة",
|
||||
"it_should_have_more_than_one_correct_answers":"يجب أن يحتوي على إجابة صحيحة"
|
||||
},
|
||||
"header": {
|
||||
"register_students": "تسجيل الطلاب",
|
||||
|
|
@ -123,7 +125,9 @@
|
|||
"personal_information": "المعلومات الشخصية",
|
||||
"address": "العنوان",
|
||||
"attachment": "المرفق",
|
||||
"subject_of_class": "مواد الصف"
|
||||
"subject_of_class": "مواد الصف",
|
||||
"this_will_un_do_all_your_changes":"سوف يؤدي هذا إلى إلغاء جميع تغييراتك",
|
||||
"edit_question":"تعديل سؤال"
|
||||
},
|
||||
"columns": {
|
||||
"id": "الرقم التعريفي",
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user