add_baseQuestion
This commit is contained in:
parent
42dcbd67cb
commit
8d9a38e1a9
|
|
@ -14,13 +14,20 @@ const Default = ({
|
|||
type,
|
||||
no_label,
|
||||
label_icon,
|
||||
label2,
|
||||
...props
|
||||
}: ValidationFieldPropsInput) => {
|
||||
const { errorMsg, isError, t } = useFormField(name, props);
|
||||
|
||||
return (
|
||||
<div className="ValidationField w-100">
|
||||
{no_label ? (
|
||||
{label2 ? (
|
||||
<label htmlFor={name} className="text">
|
||||
{label2}
|
||||
</label>
|
||||
)
|
||||
|
||||
:no_label ? (
|
||||
<label htmlFor={name} className="text">
|
||||
<span>empty</span>
|
||||
</label>
|
||||
|
|
|
|||
|
|
@ -182,6 +182,7 @@ export interface ValidationFieldPropsInput
|
|||
isDisabled?:boolean
|
||||
no_label?:string
|
||||
label_icon?:string
|
||||
label2?:string
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
38
src/Components/exercise/Header.tsx
Normal file
38
src/Components/exercise/Header.tsx
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import { useFormikContext } from 'formik';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { GoArrowSwitch } from 'react-icons/go';
|
||||
import { useObjectToEdit } from '../../zustand/ObjectToEditState';
|
||||
|
||||
const Header = () => {
|
||||
const [t] = useTranslation();
|
||||
const { values, setFieldValue,setValues } = useFormikContext<any>();
|
||||
const {isBseQuestion,set_isBseQuestion} = useObjectToEdit()
|
||||
|
||||
const handleChange = () => {
|
||||
|
||||
if (isBseQuestion) {
|
||||
set_isBseQuestion(false)
|
||||
setValues(null)
|
||||
|
||||
} else {
|
||||
|
||||
set_isBseQuestion(true)
|
||||
setValues(null)
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<header className="exercise_add_header mb-4">
|
||||
<div>
|
||||
{t("practical.add")} {t("models.exercise")}{" "}
|
||||
</div>
|
||||
<div>
|
||||
<GoArrowSwitch onClick={handleChange} className="m-2" />
|
||||
{isBseQuestion ? t("header.malty_exercise") :t("header.exercise") }
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
||||
|
|
@ -14,7 +14,7 @@ const LoginForm = () => {
|
|||
const [t] = useTranslation();
|
||||
const handelSubmit = (values: FormValues) => {
|
||||
|
||||
mutate(values );
|
||||
mutate(values);
|
||||
};
|
||||
|
||||
const { login } = useAuthState();
|
||||
|
|
|
|||
|
|
@ -4,15 +4,9 @@ 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"),
|
||||
cycle: Yup.string().required("Cycle is required"),
|
||||
branch: Yup.string().required("Branch is required"),
|
||||
term: Yup.string().required("Term is required"),
|
||||
});
|
||||
|
||||
export const initialValues: FormValues = {
|
||||
username: null,
|
||||
password: null,
|
||||
cycle: null,
|
||||
branch: null,
|
||||
term: null,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ const ModalForm: React.FC = () => {
|
|||
<Modal
|
||||
className="ModalForm"
|
||||
centered
|
||||
width={"60vw"}
|
||||
width={"40vw"}
|
||||
footer={null}
|
||||
open={isOpen === ModalEnum?.UNIT_ADD}
|
||||
onCancel={handleCancel}
|
||||
|
|
|
|||
|
|
@ -20,15 +20,6 @@ const Form = () => {
|
|||
<Col>
|
||||
<ValidationField name="name" placeholder="name" label="name" />
|
||||
</Col>
|
||||
<Col>
|
||||
<ValidationField
|
||||
type="Select"
|
||||
option={Term_Select}
|
||||
name="term"
|
||||
placeholder="term"
|
||||
label="term"
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ const ModalForm: React.FC = () => {
|
|||
<Modal
|
||||
className="ModalForm"
|
||||
centered
|
||||
width={"60vw"}
|
||||
width={"40vw"}
|
||||
footer={null}
|
||||
open={isOpen === ModalEnum?.UNIT_EDIT}
|
||||
onCancel={handleCancel}
|
||||
|
|
|
|||
|
|
@ -20,15 +20,6 @@ const Form = () => {
|
|||
<Col>
|
||||
<ValidationField name="name" placeholder="name" label="name" />
|
||||
</Col>
|
||||
<Col>
|
||||
<ValidationField
|
||||
type="Select"
|
||||
option={Term_Select}
|
||||
name="term"
|
||||
placeholder="term"
|
||||
label="term "
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ export const getInitialValues = (objectToEdit: any): any => {
|
|||
return {
|
||||
id: objectToEdit?.id,
|
||||
name: objectToEdit?.name ?? "",
|
||||
// subject_id:objectToEdit?.subject_id??null,
|
||||
term: objectToEdit?.term ?? null,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -14,6 +12,5 @@ export const getValidationSchema = () => {
|
|||
return Yup.object().shape({
|
||||
name: Yup.string().required("validation.required"),
|
||||
// subject_id: Yup.string().required('validation.required'),
|
||||
term: Yup.string().required("validation.required"),
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -69,20 +69,12 @@ export const useColumns = () => {
|
|||
render: (text, record) => record?.name,
|
||||
},
|
||||
|
||||
{
|
||||
title: t("columns.term"),
|
||||
dataIndex: "term",
|
||||
key: "term",
|
||||
align: "center",
|
||||
render: (text, record) => record?.term,
|
||||
},
|
||||
|
||||
{
|
||||
title: t("columns.lesson_count"),
|
||||
dataIndex: "lesson_count",
|
||||
key: "lesson_count",
|
||||
align: "center",
|
||||
render: (text, record) => record?.lessons?.length,
|
||||
render: (text, record) => record?.lessons_count,
|
||||
},
|
||||
|
||||
{
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ const Form = () => {
|
|||
<Col>
|
||||
<ValidationField name="name" label="name" />
|
||||
</Col>
|
||||
<Col></Col>
|
||||
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ const ModalForm: React.FC = () => {
|
|||
<Modal
|
||||
className="ModalForm"
|
||||
centered
|
||||
width={"60vw"}
|
||||
width={"40vw"}
|
||||
footer={null}
|
||||
open={isOpen === ModalEnum?.LESSON_ADD}
|
||||
onCancel={handleCancel}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ const Form = () => {
|
|||
<Col>
|
||||
<ValidationField name="name" label="name" />
|
||||
</Col>
|
||||
<Col></Col>
|
||||
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ const ModalForm: React.FC = () => {
|
|||
<Modal
|
||||
className="ModalForm"
|
||||
centered
|
||||
width={"60vw"}
|
||||
width={"40vw"}
|
||||
footer={null}
|
||||
open={isOpen === ModalEnum?.LESSON_EDIT}
|
||||
onCancel={handleCancel}
|
||||
|
|
|
|||
|
|
@ -68,15 +68,6 @@ export const useColumns = () => {
|
|||
align: "center",
|
||||
render: (text, record) => record?.name,
|
||||
},
|
||||
|
||||
{
|
||||
title: t("columns.description"),
|
||||
dataIndex: "description",
|
||||
key: "description",
|
||||
align: "center",
|
||||
render: (text, record) => record?.description,
|
||||
},
|
||||
|
||||
{
|
||||
title: can_add_Lesson ? (
|
||||
<button
|
||||
|
|
|
|||
134
src/Pages/question/AddPage.tsx
Normal file
134
src/Pages/question/AddPage.tsx
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
import React, { useEffect } from "react";
|
||||
import { Modal, Spin } from "antd";
|
||||
import FormikForm from "../../Layout/Dashboard/FormikFormModel";
|
||||
import ModelBody from "./Model/Add";
|
||||
import { getInitialValues, getValidationSchema ,getInitialValuesBase, getValidationSchemaBase} from "./Model/formUtil";
|
||||
import { useAddQuestion } from "../../api/Question";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useNavigate, 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/Add'
|
||||
import Form from './Model/Add'
|
||||
|
||||
const AddPage: React.FC = () => {
|
||||
|
||||
|
||||
const { mutate, isSuccess, isLoading ,mutateAsync} = useAddQuestion();
|
||||
const {object_to_edit} = useObjectToEdit()
|
||||
|
||||
const {subject_id} = useParams<ParamsEnum>()
|
||||
const {isBseQuestion,set_isBseQuestion} = useObjectToEdit()
|
||||
|
||||
const handleSubmit = (values: Question) => {
|
||||
const DataToSend = structuredClone(values);
|
||||
if(isBseQuestion){
|
||||
const newBseQuestion = {
|
||||
"subject_id" : subject_id,
|
||||
"content" : DataToSend?.content,
|
||||
"image": DataToSend?.image ?? "",
|
||||
"max_mark" : DataToSend?.max_mark,
|
||||
"min_mark_to_pass" : DataToSend?.min_mark_to_pass,
|
||||
"isBase" : 1,
|
||||
}
|
||||
|
||||
mutateAsync(newBseQuestion).then((data)=>{
|
||||
const newBseQuestionId = (data as any )?.data?.id ;
|
||||
const Questions = DataToSend?.Questions;
|
||||
Questions?.map((item:Question)=>{
|
||||
mutate({
|
||||
...item,
|
||||
parent_id:newBseQuestionId,
|
||||
"subject_id" : subject_id,
|
||||
})
|
||||
|
||||
})
|
||||
console.log(newBseQuestionId,"newBseQuestionId");
|
||||
|
||||
|
||||
})
|
||||
}else{
|
||||
mutate({ ...values, subject_id:subject_id });
|
||||
}
|
||||
};
|
||||
const navigate = useNavigate()
|
||||
useEffect(() => {
|
||||
if(isSuccess){
|
||||
navigate(-1)
|
||||
|
||||
}
|
||||
}, [isSuccess])
|
||||
|
||||
const handleCancel = () => {
|
||||
navigate(-1)
|
||||
};
|
||||
|
||||
const [t] = useTranslation();
|
||||
|
||||
if(isBseQuestion){
|
||||
return (
|
||||
<div className="exercise_add">
|
||||
|
||||
<FormikForm
|
||||
handleSubmit={handleSubmit}
|
||||
initialValues={getInitialValuesBase(object_to_edit)}
|
||||
validationSchema={getValidationSchemaBase}
|
||||
>
|
||||
|
||||
<main className="w-100 exercise_add_main">
|
||||
<Header/>
|
||||
<BaseForm/>
|
||||
<div className="exercise_add_buttons">
|
||||
<div onClick={handleCancel}>{t("practical.back")}</div>
|
||||
<button disabled={isLoading} className="relative" type="submit">
|
||||
{t("practical.add")}
|
||||
|
||||
{isLoading && (
|
||||
<span className="Spinier_Div">
|
||||
<Spin />
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</main>
|
||||
</FormikForm>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div className="exercise_add">
|
||||
|
||||
<FormikForm
|
||||
handleSubmit={handleSubmit}
|
||||
initialValues={getInitialValues(object_to_edit)}
|
||||
validationSchema={getValidationSchema}
|
||||
>
|
||||
|
||||
<main className="w-100 exercise_add_main">
|
||||
<Header/>
|
||||
<Form/>
|
||||
|
||||
<div className="exercise_add_buttons">
|
||||
<div onClick={handleCancel}>{t("practical.back")}</div>
|
||||
<button disabled={isLoading} className="relative" type="submit">
|
||||
{t("practical.add")}
|
||||
|
||||
{isLoading && (
|
||||
<span className="Spinier_Div">
|
||||
<Spin />
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</main>
|
||||
</FormikForm>
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddPage;
|
||||
198
src/Pages/question/EditPage.tsx
Normal file
198
src/Pages/question/EditPage.tsx
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
import React, { useEffect } from "react";
|
||||
import { Modal, Spin } from "antd";
|
||||
import FormikForm from "../../Layout/Dashboard/FormikFormModel";
|
||||
import { getInitialValues, getValidationSchema ,getInitialValuesBase, getValidationSchemaBase} from "./Model/formUtil";
|
||||
import { useAddQuestion, useGetAllQuestion, useUpdateQuestion } from "../../api/Question";
|
||||
import { useQueryClient } from "react-query";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { ParamsEnum } from "../../enums/params";
|
||||
import { useObjectToEdit } from "../../zustand/ObjectToEditState";
|
||||
import { removeStringKeys } from "../../utils/removeStringKeys";
|
||||
import SpinContainer from "../../Components/Layout/SpinContainer";
|
||||
import Header from "../../Components/exercise/Header";
|
||||
import Form from './Model/Edit'
|
||||
import BaseForm from './Model/Malty/Edit'
|
||||
import { Question } from "../../types/Item";
|
||||
|
||||
const EditPage: React.FC = () => {
|
||||
|
||||
const {question_id,subject_id} = useParams<ParamsEnum>()
|
||||
const {isBseQuestion,set_isBseQuestion} = useObjectToEdit()
|
||||
|
||||
const { mutate, isSuccess, isLoading } = useUpdateQuestion();
|
||||
const { mutate:AddQuestion} = useAddQuestion();
|
||||
|
||||
const {data,isLoading:dataLoading}= useGetAllQuestion({show:question_id})
|
||||
|
||||
const {data:Questions,isLoading:QuestionsDataLoading}= useGetAllQuestion({parent_id:question_id})
|
||||
|
||||
const object_to_edit = {...data?.data,Questions:Questions?.data } ;
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if(object_to_edit?.isBase === 1 && isBseQuestion !== true){
|
||||
set_isBseQuestion(true)
|
||||
|
||||
}
|
||||
}, [object_to_edit?.isBase])
|
||||
|
||||
|
||||
const handleSubmit = (values: any) => {
|
||||
const DataToSend = structuredClone(values);
|
||||
|
||||
console.log(isBseQuestion);
|
||||
|
||||
if(isBseQuestion){
|
||||
console.log(1);
|
||||
|
||||
const UpdateBseQuestion = {
|
||||
"id":DataToSend?.id,
|
||||
"content" : DataToSend?.content,
|
||||
"image": DataToSend?.image ?? "",
|
||||
"max_mark" : DataToSend?.max_mark,
|
||||
"min_mark_to_pass" : DataToSend?.min_mark_to_pass,
|
||||
}
|
||||
if( typeof UpdateBseQuestion?.image === "string"){
|
||||
delete UpdateBseQuestion["image"]
|
||||
}
|
||||
|
||||
mutate(UpdateBseQuestion)
|
||||
const Questions = DataToSend?.Questions;
|
||||
|
||||
Questions?.map((item:Question)=>{
|
||||
const itemToSend = structuredClone(item);
|
||||
const keysToRemove = ['image', 'answer_image'];
|
||||
const updatedObject = removeStringKeys(itemToSend, keysToRemove);
|
||||
console.log(updatedObject,"updatedObject");
|
||||
if(updatedObject?.id){
|
||||
mutate({
|
||||
...updatedObject,
|
||||
|
||||
})
|
||||
}else{
|
||||
AddQuestion({
|
||||
...updatedObject,
|
||||
parent_id:UpdateBseQuestion?.id,
|
||||
subject_id:subject_id
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
})
|
||||
}else{
|
||||
console.log(2);
|
||||
|
||||
const keysToRemove = ['image', 'answer_image'];
|
||||
const updatedObject = removeStringKeys(DataToSend, keysToRemove);
|
||||
mutate({ ...updatedObject });
|
||||
}
|
||||
};
|
||||
|
||||
const navigate = useNavigate()
|
||||
const handleCancel = () => {
|
||||
navigate(-1)
|
||||
};
|
||||
|
||||
const [t] = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
if(isSuccess){
|
||||
navigate(-1)
|
||||
}
|
||||
}, [isSuccess])
|
||||
|
||||
|
||||
console.log(object_to_edit);
|
||||
|
||||
console.log(object_to_edit?.isBase && object_to_edit?.isBase === 0);
|
||||
|
||||
|
||||
if(dataLoading && !!(object_to_edit?.isBase) && QuestionsDataLoading){
|
||||
return <SpinContainer/>
|
||||
}
|
||||
if(object_to_edit?.isBase === 1){
|
||||
|
||||
|
||||
return (
|
||||
<div className="exercise_add">
|
||||
|
||||
<FormikForm
|
||||
handleSubmit={handleSubmit}
|
||||
initialValues={getInitialValuesBase(object_to_edit)}
|
||||
validationSchema={getValidationSchemaBase}
|
||||
>
|
||||
|
||||
<main className="w-100 exercise_add_main">
|
||||
{/* <Header/> */}
|
||||
<header className="exercise_add_header mb-4">
|
||||
<div>
|
||||
{t("practical.edit")} {t("models.exercise")}{" "}
|
||||
</div>
|
||||
<div>
|
||||
|
||||
{t("header.exercise") }
|
||||
</div>
|
||||
</header>
|
||||
<BaseForm />
|
||||
<div className="exercise_add_buttons">
|
||||
<div onClick={handleCancel}>{t("practical.back")}</div>
|
||||
<button disabled={isLoading} className="relative" type="submit">
|
||||
{t("practical.edit")}
|
||||
|
||||
{isLoading && (
|
||||
<span className="Spinier_Div">
|
||||
<Spin />
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</main>
|
||||
</FormikForm>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="exercise_add">
|
||||
|
||||
<FormikForm
|
||||
handleSubmit={handleSubmit}
|
||||
initialValues={getInitialValues(object_to_edit)}
|
||||
validationSchema={getValidationSchema}
|
||||
>
|
||||
|
||||
<main className="w-100 exercise_add_main">
|
||||
{/* <Header/> */}
|
||||
<header className="exercise_add_header mb-4">
|
||||
<div>
|
||||
{t("practical.edit")} {t("models.exercise")}{" "}
|
||||
</div>
|
||||
<div>
|
||||
|
||||
{t("header.exercise") }
|
||||
</div>
|
||||
</header>
|
||||
<Form />
|
||||
<div className="exercise_add_buttons">
|
||||
<div onClick={handleCancel}>{t("practical.back")}</div>
|
||||
<button disabled={isLoading} className="relative" type="submit">
|
||||
{t("practical.edit")}
|
||||
|
||||
{isLoading && (
|
||||
<span className="Spinier_Div">
|
||||
<Spin />
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</main>
|
||||
</FormikForm>
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default EditPage;
|
||||
|
|
@ -44,17 +44,12 @@ const Form = () => {
|
|||
<ValidationField className="textarea_exercise" name="content" label="details" type="TextArea" />
|
||||
<ValidationField className="file_exercise" name="image" label="attachment" type="File" />
|
||||
|
||||
{/* <ValidationField name="isBase" label="isBase" type="Checkbox" /> */}
|
||||
<div>
|
||||
<ValidationField name="max_mark" label="max_mark" type="Number" />
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div className=" flex ">
|
||||
{/* <ValidationField name="min_mark_to_pass" label="min_mark_to_pass" type="Number" /> */}
|
||||
|
||||
{/* <ValidationField name="parent_id" label="parent_id" type="Select" option={[]} /> */}
|
||||
|
||||
</div>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,76 +0,0 @@
|
|||
import React, { useEffect } from "react";
|
||||
import { Modal, Spin } from "antd";
|
||||
import FormikForm from "../../../Layout/Dashboard/FormikFormModel";
|
||||
import ModelBody from "./Add";
|
||||
import { getInitialValues, getValidationSchema } from "./formUtil";
|
||||
import { useAddQuestion } from "../../../api/Question";
|
||||
import { useQueryClient } from "react-query";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { ParamsEnum } from "../../../enums/params";
|
||||
import { useObjectToEdit } from "../../../zustand/ObjectToEditState";
|
||||
|
||||
const ModalForm: React.FC = () => {
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const { mutate, isSuccess, isLoading } = useAddQuestion();
|
||||
const {object_to_edit} = useObjectToEdit()
|
||||
|
||||
const {subject_id} = useParams<ParamsEnum>()
|
||||
|
||||
|
||||
const handleSubmit = (values: any) => {
|
||||
console.log(values,"values");
|
||||
|
||||
mutate({ ...values, subject_id:subject_id });
|
||||
};
|
||||
const navigate = useNavigate()
|
||||
useEffect(() => {
|
||||
if(isSuccess){
|
||||
navigate(-1)
|
||||
|
||||
}
|
||||
}, [isSuccess])
|
||||
|
||||
const handleCancel = () => {
|
||||
navigate(-1)
|
||||
};
|
||||
|
||||
const [t] = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="exercise_add">
|
||||
|
||||
<FormikForm
|
||||
handleSubmit={handleSubmit}
|
||||
initialValues={getInitialValues(object_to_edit)}
|
||||
validationSchema={getValidationSchema}
|
||||
>
|
||||
|
||||
<main className="w-100 exercise_add_main">
|
||||
<header className="exercise_add_header mb-4">
|
||||
{" "}
|
||||
{t("practical.add")} {t("models.exercise")}{" "}
|
||||
</header>
|
||||
<ModelBody />
|
||||
<div className="exercise_add_buttons">
|
||||
<div onClick={handleCancel}>{t("practical.back")}</div>
|
||||
<button disabled={isLoading} className="relative" type="submit">
|
||||
{t("practical.add")}
|
||||
|
||||
{isLoading && (
|
||||
<span className="Spinier_Div">
|
||||
<Spin />
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</main>
|
||||
</FormikForm>
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ModalForm;
|
||||
|
|
@ -46,7 +46,6 @@ const Form = () => {
|
|||
|
||||
{/* <ValidationField name="isBase" label="isBase" type="Checkbox" /> */}
|
||||
<div>
|
||||
<ValidationField name="max_mark" label="max_mark" type="Number" />
|
||||
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,86 +0,0 @@
|
|||
import React, { useEffect } from "react";
|
||||
import { Modal, Spin } from "antd";
|
||||
import FormikForm from "../../../Layout/Dashboard/FormikFormModel";
|
||||
import ModelBody from "./Add";
|
||||
import { getInitialValues, getValidationSchema } from "./formUtil";
|
||||
import { useGetAllQuestion, useUpdateQuestion } from "../../../api/Question";
|
||||
import { useQueryClient } from "react-query";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { ParamsEnum } from "../../../enums/params";
|
||||
import { useObjectToEdit } from "../../../zustand/ObjectToEditState";
|
||||
import { removeStringKeys } from "../../../utils/removeStringKeys";
|
||||
import SpinContainer from "../../../Components/Layout/SpinContainer";
|
||||
|
||||
const ModalForm: React.FC = () => {
|
||||
|
||||
const {question_id,subject_id} = useParams<ParamsEnum>()
|
||||
|
||||
const { mutate, isSuccess, isLoading } = useUpdateQuestion();
|
||||
const {data,isLoading:dataLoading}= useGetAllQuestion({show:question_id})
|
||||
|
||||
const object_to_edit = data?.data ;
|
||||
|
||||
const handleSubmit = (values: any) => {
|
||||
console.log(values, "values");
|
||||
const DataToSend = structuredClone(values);
|
||||
|
||||
const keysToRemove = ['image', 'answer_image'];
|
||||
const updatedObject = removeStringKeys(DataToSend, keysToRemove);
|
||||
|
||||
mutate({ ...updatedObject });
|
||||
};
|
||||
|
||||
const navigate = useNavigate()
|
||||
const handleCancel = () => {
|
||||
navigate(-1)
|
||||
};
|
||||
|
||||
const [t] = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
if(isSuccess){
|
||||
navigate(-1)
|
||||
}
|
||||
}, [isSuccess])
|
||||
|
||||
|
||||
if(dataLoading){
|
||||
return <SpinContainer/>
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="exercise_add">
|
||||
|
||||
<FormikForm
|
||||
handleSubmit={handleSubmit}
|
||||
initialValues={getInitialValues(object_to_edit)}
|
||||
validationSchema={getValidationSchema}
|
||||
>
|
||||
|
||||
<main className="w-100 exercise_add_main">
|
||||
<header className="exercise_add_header mb-4">
|
||||
{" "}
|
||||
{t("practical.edit")} {t("models.exercise")}{" "}
|
||||
</header>
|
||||
<ModelBody />
|
||||
<div className="exercise_add_buttons">
|
||||
<div onClick={handleCancel}>{t("practical.back")}</div>
|
||||
<button disabled={isLoading} className="relative" type="submit">
|
||||
{t("practical.edit")}
|
||||
|
||||
{isLoading && (
|
||||
<span className="Spinier_Div">
|
||||
<Spin />
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</main>
|
||||
</FormikForm>
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ModalForm;
|
||||
121
src/Pages/question/Model/Malty/Add.tsx
Normal file
121
src/Pages/question/Model/Malty/Add.tsx
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
import { Col, Row } from "reactstrap";
|
||||
import React, { useEffect } from "react";
|
||||
import ValidationField from "../../../../Components/ValidationField/ValidationField";
|
||||
import { useFormikContext } from "formik";
|
||||
import { useModalState } from "../../../../zustand/Modal";
|
||||
import PdfUploader from "../../../../Components/CustomFields/PdfUploader";
|
||||
import ChoiceFields from "./ChoiceField/ChoiceFields";
|
||||
import { FaCirclePlus } from "react-icons/fa6";
|
||||
import { Choice } from "../../../../types/Item";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import DynamicTags from "./Tags/DynamicTags";
|
||||
import { useGetAllQuestion } from "../../../../api/Question";
|
||||
import QuestionFIeld from "./QuestionFIeld/QuestionFIeld";
|
||||
|
||||
const Form = () => {
|
||||
const formik = useFormikContext<any>();
|
||||
const { isOpen } = useModalState((state) => state);
|
||||
// const {data} = useGetAllQuestion();
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen === "") {
|
||||
formik.setErrors({});
|
||||
formik.resetForm();
|
||||
}
|
||||
}, [isOpen]);
|
||||
|
||||
// console.log(formik?.errors);
|
||||
|
||||
|
||||
const handleAddChoice = (parent_index:number) => {
|
||||
console.log(parent_index);
|
||||
|
||||
formik.setFieldValue(`Questions.[${parent_index}].QuestionOptions`, [...(formik?.values as any)?.Questions?.[parent_index].QuestionOptions as Choice[],
|
||||
|
||||
{
|
||||
answer:null,
|
||||
answer_image:null,
|
||||
isCorrect:0
|
||||
}])
|
||||
}
|
||||
|
||||
|
||||
const handleAddQuestion = () => {
|
||||
formik.setFieldValue('Questions', [...(formik?.values as any)?.Questions as Choice[],
|
||||
|
||||
{
|
||||
content: "",
|
||||
image: "",
|
||||
parent: '',
|
||||
isBase: 0,
|
||||
max_mark: 1,
|
||||
min_mark_to_pass: 1,
|
||||
QuestionOptions: [{ answer: null, answer_image: null, isCorrect: 0 }],
|
||||
tags: []
|
||||
}])
|
||||
|
||||
const max_mark = formik?.values?.max_mark + 1
|
||||
|
||||
formik.setFieldValue('max_mark', max_mark)
|
||||
}
|
||||
const [t] = useTranslation()
|
||||
console.log(formik.errors);
|
||||
|
||||
|
||||
return (
|
||||
<Row className="w-100">
|
||||
<div className="exercise_form">
|
||||
|
||||
<ValidationField className="textarea_exercise" name="content" label="main_question" type="TextArea" />
|
||||
<ValidationField className="file_exercise" name="image" label="attachment" type="File" />
|
||||
|
||||
<div className="">
|
||||
<ValidationField name="max_mark" label="max_mark" type="Number" className="inputSmall" disabled />
|
||||
<ValidationField name="min_mark_to_pass" label="min_mark_to_pass" className="inputSmall" type="Number" />
|
||||
|
||||
</div>
|
||||
<div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div className=" flex ">
|
||||
|
||||
</div>
|
||||
|
||||
{
|
||||
(((formik?.values as any)?.Questions as Choice[])||[]) .map((item:Choice,parent_index:number)=>{
|
||||
|
||||
return (
|
||||
<div key={parent_index}>
|
||||
|
||||
<div className="exercise_form">
|
||||
|
||||
</div>
|
||||
|
||||
{
|
||||
(((formik?.values as any)?.Questions?.[parent_index]?.QuestionOptions as Choice[])||[]) .map((item:Choice,index:number)=>{
|
||||
|
||||
return <ChoiceFields key={index} parent_index={parent_index} index={index} data={item}/>
|
||||
}
|
||||
)
|
||||
}
|
||||
<p className="add_new_button" >
|
||||
<FaCirclePlus onClick={()=> handleAddChoice(parent_index)} size={23} /> {t("header.add_new_choice")}
|
||||
</p>
|
||||
|
||||
<DynamicTags parent_index={parent_index} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
<p className="add_new_button" >
|
||||
<FaCirclePlus onClick={handleAddQuestion} size={23} /> {t("header.add_new_question")}
|
||||
</p>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
||||
export default Form;
|
||||
37
src/Pages/question/Model/Malty/ChoiceField/CheckboxField.tsx
Normal file
37
src/Pages/question/Model/Malty/ChoiceField/CheckboxField.tsx
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import React from "react";
|
||||
import useFormField from "../../../../../Hooks/useFormField";
|
||||
import { Checkbox, Form } from "antd";
|
||||
import { useFormik, useFormikContext } from "formik";
|
||||
import { useTranslation } from "react-i18next";
|
||||
const CheckboxField = ({
|
||||
name,
|
||||
label,
|
||||
isDisabled,
|
||||
onChange,
|
||||
Group,
|
||||
className,
|
||||
parent_index,
|
||||
props,
|
||||
}: any) => {
|
||||
const formik = useFormikContext<any>()
|
||||
const [t] = useTranslation()
|
||||
const CheckboxhandleChange = (value: any) => {
|
||||
console.log(value?.target?.checked);
|
||||
|
||||
formik.setFieldValue(`Questions[${parent_index}].QuestionOptions[${name}].isCorrect`, value?.target?.checked ? 1 : 0);
|
||||
};
|
||||
return (
|
||||
<div className={Group ? "d-inline mt-5 Checkbox" : ``}>
|
||||
<Checkbox
|
||||
onChange={onChange || CheckboxhandleChange}
|
||||
disabled={isDisabled}
|
||||
checked={formik.values?.Questions?.[parent_index]?.QuestionOptions?.[name]?.isCorrect === 1}
|
||||
className={className}
|
||||
>
|
||||
{t(`input.${label ? label : name}`)}
|
||||
</Checkbox>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CheckboxField;
|
||||
28
src/Pages/question/Model/Malty/ChoiceField/ChoiceFields.tsx
Normal file
28
src/Pages/question/Model/Malty/ChoiceField/ChoiceFields.tsx
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import React from 'react'
|
||||
import { Choice } from '../../../../../types/Item'
|
||||
import ValidationField from '../../../../../Components/ValidationField/ValidationField'
|
||||
import { useFormikContext } from 'formik';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { getCharFromNumber } from '../../../../../utils/getCharFromNumber';
|
||||
import CheckboxField from './CheckboxField';
|
||||
import TextField from './TextField';
|
||||
import File from './File';
|
||||
|
||||
const ChoiceFields = ({index,parent_index,data}:{index:number ,parent_index:number, data :Choice }) => {
|
||||
const formik = useFormikContext();
|
||||
|
||||
const [t] = useTranslation()
|
||||
return (
|
||||
<div className='ChoiceFields'>
|
||||
|
||||
|
||||
<TextField className="textarea_exercise" placeholder={"choice"} label2={t(`input.choice`) + ` ` + `(${(getCharFromNumber(index))})` } name={index} parent_index={parent_index} type="TextArea" />
|
||||
<File className="file_exercise" label={"attachment"} name={index} type="File" parent_index={parent_index} />
|
||||
|
||||
<CheckboxField className="" label="The_correct_answer" name={index} type="Checkbox" parent_index={parent_index} />
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ChoiceFields
|
||||
86
src/Pages/question/Model/Malty/ChoiceField/File.tsx
Normal file
86
src/Pages/question/Model/Malty/ChoiceField/File.tsx
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
import { Button, Upload, UploadFile } from "antd";
|
||||
import useFormField from "../../../../../Hooks/useFormField";
|
||||
import { UploadOutlined } from "@ant-design/icons";
|
||||
import { useMemo } from "react";
|
||||
|
||||
const File = ({
|
||||
name,
|
||||
label,
|
||||
onChange,
|
||||
isDisabled,
|
||||
placholder,
|
||||
className,
|
||||
parent_index,
|
||||
props,
|
||||
}: any) => {
|
||||
|
||||
const newName = `Questions[${parent_index}].QuestionOptions[${name}].answer_image`
|
||||
|
||||
const { formik, t, isError,errorMsg } = useFormField(newName, props);
|
||||
let imageUrl = formik?.values?.Questions?.[parent_index]?.QuestionOptions[name]?.answer_image ?? null;
|
||||
// console.log(imageUrl);
|
||||
|
||||
const fileList: UploadFile[] = useMemo(() => {
|
||||
if (!imageUrl) return [];
|
||||
|
||||
return [
|
||||
typeof imageUrl === 'string'
|
||||
? {
|
||||
uid: '-1',
|
||||
name: 'uploaded-image',
|
||||
status: 'done',
|
||||
url: imageUrl,
|
||||
thumbUrl: imageUrl,
|
||||
}
|
||||
: {
|
||||
uid: imageUrl.uid || '-1',
|
||||
name: imageUrl.name || 'uploaded-image',
|
||||
status: 'done',
|
||||
originFileObj: imageUrl,
|
||||
},
|
||||
];
|
||||
}, [imageUrl]);
|
||||
// console.log(1);
|
||||
|
||||
const FilehandleChange = (value: any) => {
|
||||
// console.log(value,"filevalue");
|
||||
if (value.fileList.length === 0) {
|
||||
formik.setFieldValue(newName, null);
|
||||
} else {
|
||||
formik.setFieldValue(`Questions[${parent_index}].QuestionOptions[${name}].answer_image`, value?.file?.originFileObj);
|
||||
|
||||
}
|
||||
};
|
||||
const customRequest = async ({ onSuccess, no_label, label_icon }: any) => {
|
||||
onSuccess();
|
||||
};
|
||||
return (
|
||||
<div className={`ValidationField upload_image_button ${className ?? ""} `}>
|
||||
<label htmlFor={name} className="text">
|
||||
{t(`input.${label || name}`)}
|
||||
</label>
|
||||
|
||||
<Upload
|
||||
disabled={isDisabled}
|
||||
listType="picture"
|
||||
maxCount={1}
|
||||
fileList={[...fileList]}
|
||||
onChange={onChange || FilehandleChange}
|
||||
customRequest={customRequest}
|
||||
className={` w-100`}
|
||||
>
|
||||
<Button
|
||||
className={isError ? "isError w-100 " : " w-100"}
|
||||
icon={<UploadOutlined />}
|
||||
>
|
||||
{placholder ?? t("input.Click_to_upload_the_image")}
|
||||
|
||||
</Button>
|
||||
<div className="Error_color"> {isError ? "required" : ""}</div>
|
||||
{errorMsg}
|
||||
</Upload>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default File;
|
||||
72
src/Pages/question/Model/Malty/ChoiceField/TextField.tsx
Normal file
72
src/Pages/question/Model/Malty/ChoiceField/TextField.tsx
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
import { Form, Input } from "antd";
|
||||
import React from "react";
|
||||
import useFormField from "../../../../../Hooks/useFormField";
|
||||
import { MdOutlineEdit } from "react-icons/md";
|
||||
import { Field } from "formik";
|
||||
const { TextArea } = Input;
|
||||
|
||||
const TextField = ({
|
||||
name,
|
||||
label,
|
||||
label2,
|
||||
placeholder,
|
||||
isDisabled,
|
||||
onChange,
|
||||
props,
|
||||
no_label,
|
||||
label_icon,
|
||||
parent_index,
|
||||
className
|
||||
}: any) => {
|
||||
const newName = `Questions[${parent_index}].QuestionOptions[${name}].answer`
|
||||
const { formik, isError, errorMsg, t } = useFormField(newName, props);
|
||||
const TextFilehandleChange = (
|
||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||
) => {
|
||||
// console.log('Change:', e.target.value);
|
||||
formik.setFieldValue(newName, e.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`ValidationField w-100 ${className ?? ""} `}>
|
||||
{no_label ? (
|
||||
<label htmlFor={name} className="text">
|
||||
<span>empty</span>
|
||||
</label>
|
||||
) : label_icon ? (
|
||||
<div className="LabelWithIcon">
|
||||
<label htmlFor={name} className="text">
|
||||
{label2 ? label2 : t(`input.${label ? label : name}`) }
|
||||
</label>
|
||||
<MdOutlineEdit size={22} style={{ color: "#A098AE" }} />
|
||||
</div>
|
||||
) : (
|
||||
<label htmlFor={name} className="text">
|
||||
{label2 ? label2 : t(`input.${label ? label : name}`) }
|
||||
</label>
|
||||
)}
|
||||
|
||||
<Form.Item
|
||||
hasFeedback
|
||||
validateStatus={isError ? "error" : ""}
|
||||
help={isError ? errorMsg : ""}
|
||||
>
|
||||
<Field
|
||||
as={TextArea}
|
||||
placeholder={t(`input.${placeholder ? placeholder : name}`)}
|
||||
name={newName}
|
||||
disabled={isDisabled}
|
||||
size="large"
|
||||
showCount
|
||||
maxLength={1000}
|
||||
onChange={onChange || TextFilehandleChange}
|
||||
style={{height:120}}
|
||||
|
||||
|
||||
/>
|
||||
</Form.Item>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(TextField);
|
||||
121
src/Pages/question/Model/Malty/Edit.tsx
Normal file
121
src/Pages/question/Model/Malty/Edit.tsx
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
import { Col, Row } from "reactstrap";
|
||||
import React, { useEffect } from "react";
|
||||
import ValidationField from "../../../../Components/ValidationField/ValidationField";
|
||||
import { useFormikContext } from "formik";
|
||||
import { useModalState } from "../../../../zustand/Modal";
|
||||
import PdfUploader from "../../../../Components/CustomFields/PdfUploader";
|
||||
import ChoiceFields from "./ChoiceField/ChoiceFields";
|
||||
import { FaCirclePlus } from "react-icons/fa6";
|
||||
import { Choice } from "../../../../types/Item";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import DynamicTags from "./Tags/DynamicTags";
|
||||
import { useGetAllQuestion } from "../../../../api/Question";
|
||||
import QuestionFIeld from "./QuestionFIeld/QuestionFIeld";
|
||||
|
||||
const Form = () => {
|
||||
const formik = useFormikContext<any>();
|
||||
const { isOpen } = useModalState((state) => state);
|
||||
// const {data} = useGetAllQuestion();
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen === "") {
|
||||
formik.setErrors({});
|
||||
formik.resetForm();
|
||||
}
|
||||
}, [isOpen]);
|
||||
|
||||
// console.log(formik?.errors);
|
||||
const [t] = useTranslation()
|
||||
|
||||
|
||||
const handleAddChoice = (parent_index:number) => {
|
||||
console.log(parent_index);
|
||||
|
||||
formik.setFieldValue(`Questions.[${parent_index}].QuestionOptions`, [...(formik?.values as any)?.Questions?.[parent_index].QuestionOptions,
|
||||
|
||||
{
|
||||
answer:null,
|
||||
answer_image:null,
|
||||
isCorrect:0
|
||||
}])
|
||||
}
|
||||
|
||||
|
||||
const handleAddQuestion = () => {
|
||||
formik.setFieldValue('Questions', [...(formik?.values as any)?.Questions,
|
||||
|
||||
{
|
||||
content: "",
|
||||
image: "",
|
||||
parent: '',
|
||||
isBase: 0,
|
||||
max_mark: 1,
|
||||
min_mark_to_pass: 1,
|
||||
QuestionOptions: [{ answer: null, answer_image: null, isCorrect: 0 }],
|
||||
tags: []
|
||||
}])
|
||||
|
||||
const max_mark = formik?.values?.max_mark + 1
|
||||
|
||||
formik.setFieldValue('max_mark', max_mark)
|
||||
}
|
||||
console.log(formik?.values);
|
||||
|
||||
return (
|
||||
<Row className="w-100">
|
||||
<div className="exercise_form">
|
||||
|
||||
<ValidationField className="textarea_exercise" name="content" label="main_question" type="TextArea" />
|
||||
<ValidationField className="file_exercise" name="image" label="attachment" type="File" />
|
||||
|
||||
<div className="">
|
||||
<ValidationField name="max_mark" label="max_mark" type="Number" className="inputSmall" disabled />
|
||||
<ValidationField name="min_mark_to_pass" label="min_mark_to_pass" className="inputSmall" type="Number" />
|
||||
|
||||
</div>
|
||||
<div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div className=" flex ">
|
||||
|
||||
</div>
|
||||
|
||||
{
|
||||
(((formik?.values as any)?.Questions)||[])?.map((item:Choice,parent_index:number)=>{
|
||||
|
||||
return (
|
||||
<div key={parent_index}>
|
||||
|
||||
<div className="exercise_form">
|
||||
|
||||
<QuestionFIeld key={parent_index} index={parent_index} data={item}/>
|
||||
</div>
|
||||
|
||||
{
|
||||
(((formik?.values as any)?.Questions?.[parent_index]?.QuestionOptions)||[]) .map((item:Choice,index:number)=>{
|
||||
|
||||
return <ChoiceFields key={index} parent_index={parent_index} index={index} data={item}/>
|
||||
}
|
||||
)
|
||||
}
|
||||
<p className="add_new_button" >
|
||||
<FaCirclePlus onClick={()=> handleAddChoice(parent_index)} size={23} /> {t("header.add_new_choice")}
|
||||
</p>
|
||||
|
||||
<DynamicTags parent_index={parent_index} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
<p className="add_new_button" >
|
||||
<FaCirclePlus onClick={handleAddQuestion} size={23} /> {t("header.add_new_question")}
|
||||
</p>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
||||
export default Form;
|
||||
85
src/Pages/question/Model/Malty/QuestionFIeld/File.tsx
Normal file
85
src/Pages/question/Model/Malty/QuestionFIeld/File.tsx
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
import { Button, Upload, UploadFile } from "antd";
|
||||
import useFormField from "../../../../../Hooks/useFormField";
|
||||
import { UploadOutlined } from "@ant-design/icons";
|
||||
import { useMemo } from "react";
|
||||
|
||||
const File = ({
|
||||
name,
|
||||
label,
|
||||
onChange,
|
||||
isDisabled,
|
||||
placholder,
|
||||
className,
|
||||
props,
|
||||
}: any) => {
|
||||
|
||||
const newName = `Questions[${name}].image`
|
||||
|
||||
const { formik, t, isError,errorMsg } = useFormField(newName, props);
|
||||
let imageUrl = formik?.values?.Questions?.[name]?.image ?? null;
|
||||
// console.log(imageUrl);
|
||||
|
||||
const fileList: UploadFile[] = useMemo(() => {
|
||||
if (!imageUrl) return [];
|
||||
|
||||
return [
|
||||
typeof imageUrl === 'string'
|
||||
? {
|
||||
uid: '-1',
|
||||
name: 'uploaded-image',
|
||||
status: 'done',
|
||||
url: imageUrl,
|
||||
thumbUrl: imageUrl,
|
||||
}
|
||||
: {
|
||||
uid: imageUrl.uid || '-1',
|
||||
name: imageUrl.name || 'uploaded-image',
|
||||
status: 'done',
|
||||
originFileObj: imageUrl,
|
||||
},
|
||||
];
|
||||
}, [imageUrl]);
|
||||
// console.log(1);
|
||||
|
||||
const FilehandleChange = (value: any) => {
|
||||
// console.log(value,"filevalue");
|
||||
if (value.fileList.length === 0) {
|
||||
formik.setFieldValue(newName, null);
|
||||
} else {
|
||||
formik.setFieldValue(`Questions[${name}].image`, value?.file?.originFileObj);
|
||||
|
||||
}
|
||||
};
|
||||
const customRequest = async ({ onSuccess, no_label, label_icon }: any) => {
|
||||
onSuccess();
|
||||
};
|
||||
return (
|
||||
<div className={`ValidationField upload_image_button ${className ?? ""} `}>
|
||||
<label htmlFor={name} className="text">
|
||||
{t(`input.${label || name}`)}
|
||||
</label>
|
||||
|
||||
<Upload
|
||||
disabled={isDisabled}
|
||||
listType="picture"
|
||||
maxCount={1}
|
||||
fileList={[...fileList]}
|
||||
onChange={onChange || FilehandleChange}
|
||||
customRequest={customRequest}
|
||||
className={` w-100`}
|
||||
>
|
||||
<Button
|
||||
className={isError ? "isError w-100 " : " w-100"}
|
||||
icon={<UploadOutlined />}
|
||||
>
|
||||
{placholder ?? t("input.Click_to_upload_the_image")}
|
||||
|
||||
</Button>
|
||||
<div className="Error_color"> {isError ? "required" : ""}</div>
|
||||
{errorMsg}
|
||||
</Upload>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default File;
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import React from 'react'
|
||||
import { Choice } from '../../../../../types/Item'
|
||||
import ValidationField from '../../../../../Components/ValidationField/ValidationField'
|
||||
import { useFormikContext } from 'formik';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { getCharFromNumber } from '../../../../../utils/getCharFromNumber';
|
||||
import TextField from './TextField';
|
||||
import File from './File';
|
||||
|
||||
const QuestionFIeld = ({index,data}:{index:number , data :Choice }) => {
|
||||
const formik = useFormikContext();
|
||||
console.log(index);
|
||||
|
||||
const [t] = useTranslation()
|
||||
return (
|
||||
<div className='ChoiceFields'>
|
||||
|
||||
<TextField className="textarea_exercise" placeholder={"choice"} label2={t(`input.question`)+ ` ` +`${index + 1}`} name={index} type="TextArea" />
|
||||
<File className="file_exercise" label={"attachment"} name={index} type="File" />
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default QuestionFIeld
|
||||
71
src/Pages/question/Model/Malty/QuestionFIeld/TextField.tsx
Normal file
71
src/Pages/question/Model/Malty/QuestionFIeld/TextField.tsx
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
import { Form, Input } from "antd";
|
||||
import React from "react";
|
||||
import useFormField from "../../../../../Hooks/useFormField";
|
||||
import { MdOutlineEdit } from "react-icons/md";
|
||||
import { Field } from "formik";
|
||||
const { TextArea } = Input;
|
||||
|
||||
const TextField = ({
|
||||
name,
|
||||
label,
|
||||
label2,
|
||||
placeholder,
|
||||
isDisabled,
|
||||
onChange,
|
||||
props,
|
||||
no_label,
|
||||
label_icon,
|
||||
className
|
||||
}: any) => {
|
||||
const newName = `Questions[${name}].content`
|
||||
const { formik, isError, errorMsg, t } = useFormField(newName, props);
|
||||
const TextFilehandleChange = (
|
||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||
) => {
|
||||
// console.log('Change:', e.target.value);
|
||||
formik.setFieldValue(newName, e.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`ValidationField w-100 ${className ?? ""} `}>
|
||||
{no_label ? (
|
||||
<label htmlFor={name} className="text">
|
||||
<span>empty</span>
|
||||
</label>
|
||||
) : label_icon ? (
|
||||
<div className="LabelWithIcon">
|
||||
<label htmlFor={name} className="text">
|
||||
{label2 ? label2 : t(`input.${label ? label : name}`) }
|
||||
</label>
|
||||
<MdOutlineEdit size={22} style={{ color: "#A098AE" }} />
|
||||
</div>
|
||||
) : (
|
||||
<label htmlFor={name} className="text">
|
||||
{label2 ? label2 : t(`input.${label ? label : name}`) }
|
||||
</label>
|
||||
)}
|
||||
|
||||
<Form.Item
|
||||
hasFeedback
|
||||
validateStatus={isError ? "error" : ""}
|
||||
help={isError ? errorMsg : ""}
|
||||
>
|
||||
<Field
|
||||
as={TextArea}
|
||||
placeholder={t(`input.${placeholder ? placeholder : name}`)}
|
||||
name={newName}
|
||||
disabled={isDisabled}
|
||||
size="large"
|
||||
showCount
|
||||
maxLength={1000}
|
||||
onChange={onChange || TextFilehandleChange}
|
||||
style={{height:120}}
|
||||
|
||||
|
||||
/>
|
||||
</Form.Item>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(TextField);
|
||||
107
src/Pages/question/Model/Malty/Tags/DynamicTags.tsx
Normal file
107
src/Pages/question/Model/Malty/Tags/DynamicTags.tsx
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
import { useFormikContext } from 'formik'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { FaCirclePlus } from 'react-icons/fa6'
|
||||
import Tag from './Tag'
|
||||
import { useObjectToEdit } from '../../../../../zustand/ObjectToEditState'
|
||||
import { useGetAllTag } from '../../../../../api/tags'
|
||||
|
||||
const DynamicTags = ({parent_index}:{parent_index:number}) => {
|
||||
|
||||
const formik = useFormikContext<any>()
|
||||
const [t] = useTranslation()
|
||||
const { Tags_search ,set_Tags_search,currentTag,current_parent_index} = useObjectToEdit();
|
||||
const {data} = useGetAllTag({
|
||||
name : Tags_search
|
||||
})
|
||||
const suggests = data?.data
|
||||
|
||||
|
||||
const handleAddChoice = () => {
|
||||
const length = formik?.values?.Questions?.[parent_index]?.tags.length;
|
||||
const lastElement = formik?.values?.Questions?.[parent_index]?.tags[length - 1]?.name;
|
||||
|
||||
if(lastElement !== ""){
|
||||
formik.setFieldValue(`Questions.[${parent_index}].tags`, [...(formik?.values as any)?.Questions?.[parent_index]?.tags as any[],
|
||||
|
||||
{
|
||||
id:length +"_new",
|
||||
name:"",
|
||||
key:length
|
||||
}])
|
||||
}else{
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
// console.log(formik?.values);
|
||||
// console.log(currentTag);
|
||||
|
||||
const handleChoice = (item: any) => {
|
||||
|
||||
const length = formik.values.tags.length;
|
||||
console.log(currentTag);
|
||||
|
||||
formik.setFieldValue(`Questions.[${parent_index}].tags[${currentTag}]`, {...item,key:length});
|
||||
set_Tags_search(null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// console.log(formik?.values?.tags?.length);
|
||||
|
||||
return (
|
||||
<div className='DynamicTags'>
|
||||
{formik?.values?.tags?.length < 1 &&
|
||||
|
||||
<p className="add_new_button" >
|
||||
<FaCirclePlus size={23} onClick={handleAddChoice} /> {t("header.add_tag")}
|
||||
</p>
|
||||
}
|
||||
|
||||
<div className="tag_container">
|
||||
<div className="tags">
|
||||
|
||||
{
|
||||
(((formik?.values as any)?.Questions?.[parent_index]?.tags as any[])||[]) .map((item:any,index:number)=>{
|
||||
|
||||
return (
|
||||
<Tag key={index} parent_index={parent_index} index={index} data={item}/>
|
||||
|
||||
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
</div>
|
||||
|
||||
{formik?.values?.Questions?.[parent_index]?.tags?.length > 0 &&
|
||||
|
||||
<p className="add_new_button" >
|
||||
<FaCirclePlus onClick={handleAddChoice} size={20} />
|
||||
</p>
|
||||
|
||||
}
|
||||
|
||||
</div>
|
||||
{Tags_search && current_parent_index === parent_index &&
|
||||
<div className="suggests">
|
||||
{suggests?.map((item:any,index:number)=>{
|
||||
console.log(current_parent_index === parent_index);
|
||||
|
||||
return (
|
||||
<div className='suggested' key={index} onClick={()=> handleChoice(item)}>
|
||||
{item?.name}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default DynamicTags
|
||||
71
src/Pages/question/Model/Malty/Tags/Tag.tsx
Normal file
71
src/Pages/question/Model/Malty/Tags/Tag.tsx
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
import { useFormikContext } from 'formik';
|
||||
import React, { useRef, useEffect } from 'react';
|
||||
import { useObjectToEdit } from '../../../../../zustand/ObjectToEditState';
|
||||
import { FaTrash } from 'react-icons/fa';
|
||||
|
||||
const Tag = ({ data, index,parent_index }: { data: any, index: number,parent_index:number }) => {
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||
const DEBOUNCE_DELAY = 500;
|
||||
const formik = useFormikContext<any>();
|
||||
const { set_Tags_search ,set_currentTag,set_current_parent_index} = useObjectToEdit();
|
||||
|
||||
useEffect(() => {
|
||||
if (inputRef.current) {
|
||||
inputRef.current.style.width = `${(formik?.values?.Questions?.[parent_index]?.tags[index]?.name?.length + 1) * 8}px`;
|
||||
}
|
||||
}, [formik?.values?.Questions?.[parent_index]?.tags[index]?.name]);
|
||||
|
||||
const handleEditInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
// console.log(e.target.value);
|
||||
formik.setFieldValue(`Questions.[${parent_index}].tags[${index}].name`, e.target.value);
|
||||
set_currentTag(index)
|
||||
set_current_parent_index(parent_index)
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
}
|
||||
|
||||
timeoutRef.current = setTimeout(() => {
|
||||
set_Tags_search(e.target.value)
|
||||
}, DEBOUNCE_DELAY);
|
||||
};
|
||||
|
||||
const handleDeleteChoice = () => {
|
||||
console.log(data);
|
||||
|
||||
// Create a copy of current tags array
|
||||
const currentTags = [...formik.values.tags];
|
||||
|
||||
// Remove the item at the specified index from the array
|
||||
currentTags.splice(index, 1);
|
||||
|
||||
console.log(currentTags); // Log the updated tags array
|
||||
|
||||
// Update formik field value with the updated tags array
|
||||
formik.setFieldValue(`Questions.[${parent_index}].tags`, currentTags);
|
||||
|
||||
// Reset search state if needed
|
||||
set_Tags_search(null);
|
||||
};
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div className='tag'>
|
||||
<input
|
||||
ref={inputRef}
|
||||
className="tagInput"
|
||||
type="text"
|
||||
value={formik?.values?.Questions?.[parent_index]?.tags[index]?.name}
|
||||
onChange={handleEditInputChange}
|
||||
|
||||
/>
|
||||
<FaTrash onClick={handleDeleteChoice}/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Tag;
|
||||
|
||||
|
||||
|
||||
|
|
@ -7,7 +7,8 @@ const Tag = ({ data, index }: { data: any, index: number }) => {
|
|||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const formik = useFormikContext<any>();
|
||||
const { set_Tags_search ,set_currentTag} = useObjectToEdit();
|
||||
|
||||
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||
const DEBOUNCE_DELAY = 500;
|
||||
useEffect(() => {
|
||||
if (inputRef.current) {
|
||||
inputRef.current.style.width = `${(formik?.values?.tags[index]?.name?.length + 1) * 8}px`;
|
||||
|
|
@ -17,9 +18,15 @@ const Tag = ({ data, index }: { data: any, index: number }) => {
|
|||
const handleEditInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
// console.log(e.target.value);
|
||||
formik.setFieldValue(`tags[${index}].name`, e.target.value);
|
||||
set_Tags_search(e.target.value)
|
||||
// set_Tags_search(e.target.value)
|
||||
set_currentTag(index)
|
||||
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
}
|
||||
|
||||
timeoutRef.current = setTimeout(() => {
|
||||
set_Tags_search(e.target.value)
|
||||
}, DEBOUNCE_DELAY);
|
||||
};
|
||||
|
||||
const handleInputBlur = () => {
|
||||
|
|
|
|||
|
|
@ -3,26 +3,24 @@ import { Question } from "../../../types/Item";
|
|||
|
||||
|
||||
export const getInitialValues = (objectToEdit: Question): any => {
|
||||
const tags = objectToEdit?.tags?.map((item:any,index:number)=>{
|
||||
return {...item,key:index}
|
||||
});
|
||||
console.log(objectToEdit,"objectToEdit");
|
||||
const tags = objectToEdit?.tags?.map((item: any, index: number) => {
|
||||
return { ...item, key: index }
|
||||
});
|
||||
|
||||
return {
|
||||
id: objectToEdit?.id ?? null,
|
||||
content: objectToEdit?.content ?? "",
|
||||
image: objectToEdit?.image ?? "",
|
||||
subject_id:objectToEdit?.subject_id??'',
|
||||
isBase:objectToEdit?.isBase??'',
|
||||
max_mark:objectToEdit?.max_mark??null,
|
||||
min_mark_to_pass:1,
|
||||
parent:objectToEdit?.parent??'',
|
||||
QuestionOptions: objectToEdit?.QuestionOptions ?? [{answer:null,answer_image:null,isCorrect:0}],
|
||||
tags : tags ??[]
|
||||
subject_id: objectToEdit?.subject_id ?? '',
|
||||
isBase: objectToEdit?.isBase,
|
||||
max_mark: 1,
|
||||
min_mark_to_pass: 1,
|
||||
parent: objectToEdit?.parent ?? '',
|
||||
QuestionOptions: objectToEdit?.QuestionOptions ?? [],
|
||||
tags: tags ?? [],
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
export const getValidationSchema = () => {
|
||||
// validate input
|
||||
return Yup.object().shape({
|
||||
|
|
@ -30,13 +28,63 @@ export const getValidationSchema = () => {
|
|||
content: Yup.string().required("validation.required"),
|
||||
max_mark: Yup.number().required("validation.required").min(Yup.ref("min_mark_to_pass"),"validation.max_mark_must_be_greater_than_min_mark_to_pass"),
|
||||
min_mark_to_pass: Yup.number().required("validation.required"),
|
||||
|
||||
QuestionOptions: Yup.array().of(
|
||||
Yup.object().shape({
|
||||
answer: Yup.string().required('details name is required'),
|
||||
answer: Yup.string().required("validation.required"),
|
||||
answer_image: Yup.string().nullable(),
|
||||
isCorrect: Yup.boolean()
|
||||
})
|
||||
).required('Params are required')
|
||||
).nullable('Params are required')
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
export const getInitialValuesBase = (objectToEdit: Question): any => {
|
||||
const tags = objectToEdit?.tags?.map((item: any, index: number) => {
|
||||
return { ...item, key: index }
|
||||
});
|
||||
console.log(objectToEdit);
|
||||
|
||||
const questions = objectToEdit?.Questions ?? [];
|
||||
|
||||
|
||||
return {
|
||||
id: objectToEdit?.id ?? null,
|
||||
content: objectToEdit?.content ?? "",
|
||||
image: objectToEdit?.image ?? "",
|
||||
subject_id: objectToEdit?.subject_id ?? '',
|
||||
isBase: objectToEdit?.isBase,
|
||||
max_mark: questions.length ?? 1,
|
||||
min_mark_to_pass: 1,
|
||||
parent: objectToEdit?.parent ?? '',
|
||||
tags: tags ?? [],
|
||||
Questions: questions,
|
||||
};
|
||||
};
|
||||
|
||||
export const getValidationSchemaBase = () => {
|
||||
// validate input
|
||||
return Yup.object().shape({
|
||||
image: Yup.string().nullable(),
|
||||
content: Yup.string().required("validation.required"),
|
||||
max_mark: Yup.number().required("validation.required").min(Yup.ref("min_mark_to_pass"),"validation.max_mark_must_be_greater_than_min_mark_to_pass"),
|
||||
min_mark_to_pass: Yup.number().required("validation.required"),
|
||||
Questions: Yup.array().of(
|
||||
Yup.object().shape({
|
||||
image: Yup.string().nullable(),
|
||||
content: Yup.string().required("validation.required"),
|
||||
max_mark: Yup.number().required("validation.required").min(Yup.ref("min_mark_to_pass"),"validation.max_mark_must_be_greater_than_min_mark_to_pass"),
|
||||
min_mark_to_pass: Yup.number().required("validation.required"),
|
||||
QuestionOptions: Yup.array().of(
|
||||
Yup.object().shape({
|
||||
answer: Yup.string().required("validation.required"),
|
||||
answer_image: Yup.string().nullable(),
|
||||
isCorrect: Yup.boolean()
|
||||
})
|
||||
).nullable('required')
|
||||
})
|
||||
),
|
||||
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@ import { useParams } from "react-router-dom";
|
|||
import { ParamsEnum } from "../../enums/params";
|
||||
|
||||
const App: React.FC = () => {
|
||||
const {unit_id} = useParams<ParamsEnum>()
|
||||
const response = useGetAllQuestion({ unit_id:unit_id, pagination: true});
|
||||
const {subject_id} = useParams<ParamsEnum>()
|
||||
const response = useGetAllQuestion({ subject_id:subject_id, pagination: true});
|
||||
|
||||
return <DataTable response={response} useColumns={useColumns} />;
|
||||
return <DataTable response={response} useColumns={useColumns} />;
|
||||
};
|
||||
|
||||
export default App;
|
||||
|
|
|
|||
|
|
@ -8,13 +8,7 @@ import { useModalState } from "../../../zustand/Modal";
|
|||
import useSearchQuery from "../../../api/utils/useSearchQuery";
|
||||
|
||||
const Form = () => {
|
||||
const [searchQuery] = useSearchQuery("techer_name");
|
||||
|
||||
const { data , isLoading } = useGetAllTeacher({
|
||||
name: searchQuery,
|
||||
|
||||
});
|
||||
const SelectData = useFormatDataToSelect(data?.data);
|
||||
const { isOpen } = useModalState((state) => state);
|
||||
const formik = useFormikContext<any>();
|
||||
useEffect(() => {
|
||||
|
|
@ -28,15 +22,7 @@ const Form = () => {
|
|||
<Row className="w-100">
|
||||
<Col>
|
||||
<ValidationField name="name" label="name" />
|
||||
<ValidationField
|
||||
type="Search"
|
||||
option={SelectData}
|
||||
isMulti
|
||||
name="teacher_ids"
|
||||
label="teacher_name"
|
||||
searchBy="techer_name"
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
|
||||
</Col>
|
||||
<Col>
|
||||
<ValidationField type="File" name="image" label="image" />
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import { useTranslation } from "react-i18next";
|
|||
|
||||
const ModalForm: React.FC = () => {
|
||||
const { isOpen, setIsOpen } = useModalState((state) => state);
|
||||
const { course_id } = useParams();
|
||||
const { mutate, isSuccess, isLoading } = useAddSubject();
|
||||
const { set_object_to_edit } = useObjectToEdit();
|
||||
|
||||
|
|
@ -27,7 +26,7 @@ const ModalForm: React.FC = () => {
|
|||
// console.log(values,"values");
|
||||
mutate({
|
||||
...values,
|
||||
course_id: course_id,
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -8,12 +8,6 @@ import { useFormikContext } from "formik";
|
|||
import useSearchQuery from "../../../api/utils/useSearchQuery";
|
||||
|
||||
const Form = () => {
|
||||
const [searchQuery] = useSearchQuery("techer_name");
|
||||
|
||||
const { data , isLoading } = useGetAllTeacher({
|
||||
name: searchQuery,
|
||||
});
|
||||
const SelectData = useFormatDataToSelect(data?.data);
|
||||
|
||||
const { isOpen } = useModalState((state) => state);
|
||||
const formik = useFormikContext();
|
||||
|
|
@ -27,15 +21,7 @@ const Form = () => {
|
|||
<Row className="w-100">
|
||||
<Col>
|
||||
<ValidationField name="name" label="name" />
|
||||
<ValidationField
|
||||
type="Search"
|
||||
searchBy="techer_name"
|
||||
option={SelectData}
|
||||
isMulti
|
||||
name="teacher_ids"
|
||||
label="teacher_name"
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
|
||||
</Col>
|
||||
<Col>
|
||||
<ValidationField type="File" name="image" label="image" />
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ const ModalForm: React.FC = () => {
|
|||
<Modal
|
||||
className="ModalForm"
|
||||
centered
|
||||
width={"60vw"}
|
||||
width={"40vw"}
|
||||
footer={null}
|
||||
open={isOpen === ModalEnum?.UNIT_ADD}
|
||||
onCancel={handleCancel}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ const ModalForm: React.FC = () => {
|
|||
<Modal
|
||||
className="ModalForm"
|
||||
centered
|
||||
width={"60vw"}
|
||||
width={"40vw"}
|
||||
footer={null}
|
||||
open={isOpen === ModalEnum?.UNIT_EDIT}
|
||||
onCancel={handleCancel}
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ const Tags = React.lazy(() => import("./Pages/Tags/Page"));
|
|||
const Unit = React.lazy(() => import("./Pages/Unit/Page"));
|
||||
const Lesson = React.lazy(() => import("./Pages/lesson/Page"));
|
||||
const Question = React.lazy(() => import('./Pages/question/Page'))
|
||||
const AddQuestion = React.lazy(() => import('./Pages/question/Model/AddModel'))
|
||||
const EditQuestion = React.lazy(() => import('./Pages/question/Model/EditModel'))
|
||||
const AddQuestionPage = React.lazy(() => import('./Pages/question/AddPage'))
|
||||
const EditQuestionPage = React.lazy(() => import('./Pages/question/EditPage'))
|
||||
|
||||
|
||||
// const QuestionChildren = React.lazy(() => import('./Pages/question/children/Page'))
|
||||
|
|
@ -90,14 +90,14 @@ export const CrudRoute: TCrudRoute[] = [
|
|||
},
|
||||
{
|
||||
header: "page_header.add_Question",
|
||||
element: <AddQuestion />,
|
||||
element: <AddQuestionPage />,
|
||||
path: `/${ABILITIES_ENUM?.SUBJECT}/:${ParamsEnum?.SUBJECT_ID}/${ABILITIES_ENUM?.UNIT}/:${ParamsEnum?.UNIT_ID}/${ABILITIES_ENUM?.LESSON}/:${ParamsEnum?.LESSON_ID}/${ABILITIES_ENUM?.QUESTION}/add`,
|
||||
abilities: ABILITIES_ENUM?.QUESTION,
|
||||
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
||||
},
|
||||
{
|
||||
header: "page_header.edit_Question",
|
||||
element: <EditQuestion />,
|
||||
element: <EditQuestionPage />,
|
||||
path: `/${ABILITIES_ENUM?.SUBJECT}/:${ParamsEnum?.SUBJECT_ID}/${ABILITIES_ENUM?.UNIT}/:${ParamsEnum?.UNIT_ID}/${ABILITIES_ENUM?.LESSON}/:${ParamsEnum?.LESSON_ID}/${ABILITIES_ENUM?.QUESTION}/:${ParamsEnum?.QUESTION_ID}`,
|
||||
abilities: ABILITIES_ENUM?.QUESTION,
|
||||
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
||||
|
|
|
|||
|
|
@ -107,4 +107,14 @@
|
|||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.exercise_add_header{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.inputSmall{
|
||||
width: 100px;
|
||||
}
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
export const BaseURL = "http://192.168.1.108:8000/api/";
|
||||
// export const BaseURL = "http://192.168.1.108:8000/api/";
|
||||
export const BaseURL = "http://127.0.0.1:8000/api/";
|
||||
|
||||
// export const BaseURL = "https://school-back-dev.point-dev.net/api/";
|
||||
|
||||
export const ImageBaseURL = "http://192.168.1.9:8000/";
|
||||
|
|
|
|||
|
|
@ -99,10 +99,13 @@
|
|||
"change_your_current_password": "تغير كلمة السر الحالية",
|
||||
"view_cycle_for_this_branch": "مشاهدة الدورات في هذا الفرع",
|
||||
"view_term_for_this_cycle": "مشاهدة الفصول في هذة السنة دراسية",
|
||||
"add_new_choice":"إضافة خيار آخر",
|
||||
"add_new_choice":"إضافة خيار ",
|
||||
"add_tag":"إضافة كلمة مفتاحية",
|
||||
"add_synonyms":"إضافة مرادفات",
|
||||
"add_Question":"إضافة اسئلة"
|
||||
"add_Question":"إضافة اسئلة",
|
||||
"malty_exercise":"تمرين متعدد",
|
||||
"add_new_question":"اضافة سؤال جديد",
|
||||
"exercise":"تمارين"
|
||||
|
||||
},
|
||||
"columns": {
|
||||
|
|
@ -331,7 +334,9 @@
|
|||
"exercise":"تمارين",
|
||||
"max_mark":"العلامة الكاملة",
|
||||
"min_mark_to_pass" : "علامة النجاح",
|
||||
"isBase":"سؤال رئيسي"
|
||||
"isBase":"سؤال رئيسي",
|
||||
"main_question":"النص الأساسي ",
|
||||
"question":"السؤال"
|
||||
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
export interface FormValues {
|
||||
username: string | null;
|
||||
password: string | null;
|
||||
cycle: string | null;
|
||||
branch: string | null;
|
||||
term: string | null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ export interface Unit {
|
|||
description: string | null;
|
||||
subject_id: number;
|
||||
term: term_type;
|
||||
lessons_count:number;
|
||||
lessons: Lesson[];
|
||||
}
|
||||
|
||||
|
|
@ -313,6 +314,7 @@ export interface Question {
|
|||
max_mark: number;
|
||||
min_mark_to_pass: number;
|
||||
image: string | null;
|
||||
Questions?:any[]
|
||||
QuestionOptions: QuestionOption[];
|
||||
tags: tags[]; // Assuming tags are strings, adjust as per actual data type
|
||||
}
|
||||
|
|
@ -21,7 +21,7 @@ const useAuthState = create<AuthStore>((set) => {
|
|||
const storedAbilities = localStorage.getItem(ABILITIES_KEY);
|
||||
|
||||
return {
|
||||
isAuthenticated: !!storedToken && !!storedAbilities,
|
||||
isAuthenticated: !!storedToken,
|
||||
token: storedToken,
|
||||
abilities: storedAbilities,
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,10 @@ interface ModelState {
|
|||
set_Tags_query: (data: any) => void;
|
||||
currentTag: any;
|
||||
set_currentTag: (data: any) => void;
|
||||
|
||||
current_parent_index: any;
|
||||
set_current_parent_index: (data: any) => void;
|
||||
isBseQuestion: boolean;
|
||||
set_isBseQuestion: (data: any) => void;
|
||||
}
|
||||
|
||||
export const useObjectToEdit = create<ModelState>((set) => ({
|
||||
|
|
@ -33,4 +36,8 @@ export const useObjectToEdit = create<ModelState>((set) => ({
|
|||
set_Tags_query: (data) => set(() => ({ Tags_query: data })),
|
||||
currentTag: null,
|
||||
set_currentTag: (data) => set(() => ({ currentTag: data })),
|
||||
current_parent_index: null,
|
||||
set_current_parent_index: (data) => set(() => ({ current_parent_index: data })),
|
||||
isBseQuestion: false,
|
||||
set_isBseQuestion: (data) => set(() => ({ isBseQuestion: data })),
|
||||
}));
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user