diff --git a/.vscode/settings.json b/.vscode/settings.json index 9537424..54fb8c9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,8 +10,10 @@ "Groupbutton", "handelnavigate", "Karim", + "Popconfirm", "queryqlent", "registraion", + "Sellcast", "SENDNOTIFICATION", "setdateparams", "szhsin", diff --git a/src/Components/CustomFields/ImageBoxField/ImageBoxField.tsx b/src/Components/CustomFields/ImageBoxField/ImageBoxField.tsx index 7e1b753..230058e 100644 --- a/src/Components/CustomFields/ImageBoxField/ImageBoxField.tsx +++ b/src/Components/CustomFields/ImageBoxField/ImageBoxField.tsx @@ -63,9 +63,9 @@ const ImageBoxField = ({ name }: any) => {
hidden
)} -
+
{imagePreview ? ( - Preview + Preview ) : ( )} diff --git a/src/Components/ValidationField/View/TextField.tsx b/src/Components/ValidationField/View/TextField.tsx index 95db0f1..35babba 100644 --- a/src/Components/ValidationField/View/TextField.tsx +++ b/src/Components/ValidationField/View/TextField.tsx @@ -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 = ( @@ -25,6 +25,7 @@ const TextField = ({ ) => { formik.setFieldValue(name, e.target.value); }; + return (
diff --git a/src/Components/ValidationField/utils/ValidationField.scss b/src/Components/ValidationField/utils/ValidationField.scss index 3f797be..d158b96 100644 --- a/src/Components/ValidationField/utils/ValidationField.scss +++ b/src/Components/ValidationField/utils/ValidationField.scss @@ -15,6 +15,8 @@ .text, .ant-form-item { margin-bottom: 7px !important; + font-weight: bold; + font-size: 19px; > span { color: transparent; } @@ -65,3 +67,15 @@ .ant-input-textarea-affix-wrapper.ant-input-affix-wrapper { height: 120px; } + + + +//// malty select +/// + .ant-select-multiple{ + height: auto !important; + min-height: 40px; + .ant-select-selector{ + min-height: 40px; + } + } \ No newline at end of file diff --git a/src/Components/exercise/Header.tsx b/src/Components/exercise/Header.tsx index 2914ff1..a524b5f 100644 --- a/src/Components/exercise/Header.tsx +++ b/src/Components/exercise/Header.tsx @@ -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(); 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 = (

@@ -52,10 +62,21 @@ const Header = () => {

- + {confirm()}} + defaultOpen={false} + + > + + {isBseQuestion || values?.isBase === 1 ? t("header.malty_exercise") : t("header.exercise")} + +
); diff --git a/src/Hooks/useFormField.tsx b/src/Hooks/useFormField.tsx index 81a7f03..c136873 100644 --- a/src/Hooks/useFormField.tsx +++ b/src/Hooks/useFormField.tsx @@ -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(); diff --git a/src/Layout/Dashboard/DeleteModels.tsx b/src/Layout/Dashboard/DeleteModels.tsx index dc88705..dd9fed4 100644 --- a/src/Layout/Dashboard/DeleteModels.tsx +++ b/src/Layout/Dashboard/DeleteModels.tsx @@ -73,7 +73,7 @@ const DeleteModels: React.FC = ({ = ({ initialValues={initialValues} validationSchema={validationSchema} onSubmit={handleSubmit} + > {(formik) => { useEffect(() => { diff --git a/src/Layout/Dashboard/PageHeader.tsx b/src/Layout/Dashboard/PageHeader.tsx index c1e30dc..85085c8 100644 --- a/src/Layout/Dashboard/PageHeader.tsx +++ b/src/Layout/Dashboard/PageHeader.tsx @@ -1,5 +1,4 @@ -import React from "react"; -import SearchBar from "../../Components/Ui/SearchBar/SearchBar"; + import { Button } from "antd"; import { BsPlusCircleFill } from "react-icons/bs"; import { useNavigate } from "react-router-dom"; @@ -8,8 +7,7 @@ import useModalHandler from "../../utils/useModalHandler"; import { MdOutlineArrowForwardIos } from "react-icons/md"; import { deletePathSegments } from "../../utils/deletePathSegments"; import { getPrevPathRoute } from "../../utils/getPrevPathRoute"; -import { usePageTitleState } from "../../zustand/PageTitleState"; -import FillterForm from "../Ui/FillterForm"; +import PageTitleComponent from "./PageTitle"; const PageHeader = ({ canAdd, @@ -35,20 +33,20 @@ const PageHeader = ({ if (PrevPath === 0) { return; } - navigate(deletePathSegments(location.pathname, PrevPath)); + // navigate(deletePathSegments(location.pathname, PrevPath)); }; const handleNavigateToPage = (location: string) => { - navigate(location); + // navigate(location); }; + console.log(); - const { PageTitle } = usePageTitleState(); return (

{t(`PageTitle.${pageTitle}`)}

- {PageTitle} +
{ addModal ? canAdd && ( diff --git a/src/Layout/Dashboard/PageTitle.tsx b/src/Layout/Dashboard/PageTitle.tsx new file mode 100644 index 0000000..4c3d757 --- /dev/null +++ b/src/Layout/Dashboard/PageTitle.tsx @@ -0,0 +1,30 @@ +import React from 'react' +import { useLocation, useNavigate } from 'react-router-dom' +import { usePageTitleState } from '../../zustand/PageTitleState' + +const PageTitleComponent = () => { + + const {PageTitle,setPageTitle} = usePageTitleState() + const navigate = useNavigate() + const location = useLocation() + const handleNavigate = (path:string)=>{ + const currentPath = location.pathname ; + const newPath = currentPath?.split(path)?.[0] + path ; + if(newPath !== currentPath){ + navigate(newPath) + } + } + return ( +
+ {(Array.isArray(PageTitle) ? PageTitle : [])?.map((item,index)=>{ + return ( +
handleNavigate(item?.path)}> + {item?.name} / +
+ ) + })} +
+ ) +} + +export default PageTitleComponent \ No newline at end of file diff --git a/src/Pages/Admin/Grade/Page.tsx b/src/Pages/Admin/Grade/Page.tsx index 05bf248..b068d9b 100644 --- a/src/Pages/Admin/Grade/Page.tsx +++ b/src/Pages/Admin/Grade/Page.tsx @@ -20,7 +20,10 @@ const TableHeader = () => { const [t] = useTranslation(); const deleteMutation = useDeleteGrade(); - useSetPageTitle(t(`page_header.grade`)); + useSetPageTitle([ + {name:`${t(`page_header.home`)}`, path:"/"}, + {name:`${t(`page_header.grade`)}`, path:"grade"} + ]); return (
diff --git a/src/Pages/Admin/Param/Page.tsx b/src/Pages/Admin/Param/Page.tsx index 183af03..63b0320 100644 --- a/src/Pages/Admin/Param/Page.tsx +++ b/src/Pages/Admin/Param/Page.tsx @@ -18,7 +18,11 @@ const DeleteModalForm = lazy( const TableHeader = () => { const [t] = useTranslation(); - useSetPageTitle(t(`page_header.param`)); + + useSetPageTitle([ + {name:`${t(`page_header.home`)}`, path:"/"}, + {name:`${t(`page_header.param`)}`, path:"param"} + ]); const deleteMutation = useDeleteParam(); return (
diff --git a/src/Pages/Admin/QuestionBank/Model/AddModel.tsx b/src/Pages/Admin/QuestionBank/Model/AddModel.tsx new file mode 100644 index 0000000..348426b --- /dev/null +++ b/src/Pages/Admin/QuestionBank/Model/AddModel.tsx @@ -0,0 +1,33 @@ +import React from "react"; +import { getInitialValues, getValidationSchema } from "./formUtil"; +import { ModalEnum } from "../../../../enums/Model"; +import LayoutModel from "../../../../Layout/Dashboard/LayoutModel"; +import { QueryStatusEnum } from "../../../../enums/QueryStatus"; +import ModelForm from "./ModelForm"; +import { useAddGrade } from "../../../../api/grade"; + +const AddModel: React.FC = () => { + const { mutate, status } = useAddGrade(); + + const handleSubmit = (values: any) => { + mutate({ + ...values, + }); + }; + return ( + <> + + + + + ); +}; + +export default AddModel; diff --git a/src/Pages/Admin/QuestionBank/Model/EditModel.tsx b/src/Pages/Admin/QuestionBank/Model/EditModel.tsx new file mode 100644 index 0000000..a2e1fdb --- /dev/null +++ b/src/Pages/Admin/QuestionBank/Model/EditModel.tsx @@ -0,0 +1,38 @@ +import React from "react"; +import { getInitialValues, getValidationSchema } from "./formUtil"; +import { ModalEnum } from "../../../../enums/Model"; +import LayoutModel from "../../../../Layout/Dashboard/LayoutModel"; +import ModelForm from "./ModelForm"; +import { QueryStatusEnum } from "../../../../enums/QueryStatus"; +import { useObjectToEdit } from "../../../../zustand/ObjectToEditState"; +import { useUpdateQuestion } from "../../../../api/Question"; +import { handelImageState } from "../../../../utils/DataToSendImageState"; + +const EditModel: React.FC = () => { + const { mutate, status } = useUpdateQuestion(); + const { objectToEdit } = useObjectToEdit((state) => state); + + const handleSubmit = (values: any) => { + const Data_to_send = { ...values }; + const handelImage = handelImageState(Data_to_send, "icon"); + mutate(handelImage); + }; + + return ( + <> + + + + + ); +}; + +export default EditModel; diff --git a/src/Pages/Admin/QuestionBank/Model/FilterForm.tsx b/src/Pages/Admin/QuestionBank/Model/FilterForm.tsx new file mode 100644 index 0000000..c870850 --- /dev/null +++ b/src/Pages/Admin/QuestionBank/Model/FilterForm.tsx @@ -0,0 +1,20 @@ +import React from "react"; +import ValidationField from "../../../../Components/ValidationField/ValidationField"; +import { Col, Row } from "reactstrap"; +import { useFormikContext } from "formik"; + +const FilterForm = () => { + const formik = useFormikContext(); + + return ( +
+ + + + + +
+ ); +}; + +export default FilterForm; diff --git a/src/Pages/Admin/QuestionBank/Model/ModelForm.tsx b/src/Pages/Admin/QuestionBank/Model/ModelForm.tsx new file mode 100644 index 0000000..b18fe6f --- /dev/null +++ b/src/Pages/Admin/QuestionBank/Model/ModelForm.tsx @@ -0,0 +1,17 @@ +import { Col, Row } from "reactstrap"; +import ValidationField from "../../../../Components/ValidationField/ValidationField"; + +const Form = () => { + return ( + + + + + + + + + ); +}; + +export default Form; diff --git a/src/Pages/Admin/QuestionBank/Model/formUtil.ts b/src/Pages/Admin/QuestionBank/Model/formUtil.ts new file mode 100644 index 0000000..77f69bf --- /dev/null +++ b/src/Pages/Admin/QuestionBank/Model/formUtil.ts @@ -0,0 +1,19 @@ +import * as Yup from "yup"; +import { Grade, GradeInitialValues } from "../../../../types/Grade"; + +export const getInitialValues = ( + objectToEdit: Partial, +): GradeInitialValues => { + return { + id: objectToEdit?.id, + name: objectToEdit?.name ?? "", + icon: objectToEdit?.icon ?? "", + }; +}; + +export const getValidationSchema = () => { + // validate input + return Yup.object().shape({ + name: Yup.string().required("validation.required"), + }); +}; diff --git a/src/Pages/Admin/QuestionBank/Page.tsx b/src/Pages/Admin/QuestionBank/Page.tsx new file mode 100644 index 0000000..91c7f43 --- /dev/null +++ b/src/Pages/Admin/QuestionBank/Page.tsx @@ -0,0 +1,49 @@ +import { useTranslation } from "react-i18next"; +import { lazy, Suspense } from "react"; +import { Spin } from "antd"; +import useSetPageTitle from "../../../Hooks/useSetPageTitle"; +import { ModalEnum } from "../../../enums/Model"; +import { useDeleteQuestion } from "../../../api/Question"; +import PageHeader from "../../../Layout/Dashboard/PageHeader"; +import FilterLayout from "../../../Layout/Dashboard/FilterLayout"; +import FilterForm from "./Model/FilterForm"; +import { canAddQuestionBank } from "../../../utils/hasAbilityFn"; + +const Table = lazy(() => import("./Table")); +const AddModalForm = lazy(() => import("./Model/AddModel")); +const EditModalForm = lazy(() => import("./Model/EditModel")); +const DeleteModalForm = lazy( + () => import("../../../Layout/Dashboard/DeleteModels"), +); + +const TableHeader = () => { + const [t] = useTranslation(); + const deleteMutation = useDeleteQuestion(); + + + useSetPageTitle([ + {name:`${t(`page_header.home`)}`, path:"/"}, + {name:`${t(`page_header.Question`)}`, path:"Question"} + ]); + return ( +
+ }> + + } filterTitle="table.QuestionBank" /> + + + + + + + ); +}; + +export default TableHeader; diff --git a/src/Pages/Admin/QuestionBank/Table.tsx b/src/Pages/Admin/QuestionBank/Table.tsx new file mode 100644 index 0000000..37f483c --- /dev/null +++ b/src/Pages/Admin/QuestionBank/Table.tsx @@ -0,0 +1,18 @@ +import { useColumns } from "./useTableColumns"; +import React from "react"; +import DataTable from "../../../Layout/Dashboard/Table/DataTable"; +import { useGetAllQuestion } from "../../../api/Question"; +import { useFilterState } from "../../../Components/Utils/Filter/FilterState"; + +const App: React.FC = () => { + const { filterState } = useFilterState(); + + const response = useGetAllQuestion({ + pagination: true, + ...filterState, + }); + + return ; +}; + +export default App; diff --git a/src/Pages/Admin/QuestionBank/useTableColumns.tsx b/src/Pages/Admin/QuestionBank/useTableColumns.tsx new file mode 100644 index 0000000..632669b --- /dev/null +++ b/src/Pages/Admin/QuestionBank/useTableColumns.tsx @@ -0,0 +1,123 @@ +import { TableColumnsType } from "antd"; +import { Question } from "../../../types/Item"; +import { FaPlus } from "react-icons/fa"; +import { ModalEnum } from "../../../enums/Model"; +import { useObjectToEdit } from "../../../zustand/ObjectToEditState"; +import { useTranslation } from "react-i18next"; +import { ABILITIES_ENUM } from "../../../enums/abilities"; +import { useNavigate } from "react-router-dom"; +import { useModalState } from "../../../zustand/Modal"; +import { + canAddQuestion, + canDeleteQuestion, + canEditQuestion, +} from "../../../utils/hasAbilityFn"; +import ActionButtons from "../../../Components/Table/ActionButtons"; + +export const useColumns = () => { + const { setObjectToEdit } = useObjectToEdit((state) => state); + const navigate = useNavigate(); + const { setIsOpen } = useModalState((state) => state); + + const handelAdd = () => { + setObjectToEdit({}); + navigate(`${ABILITIES_ENUM?.QUESTION}/add`); + }; + + const handelDelete = (data: any) => { + setObjectToEdit(data); + setIsOpen(ModalEnum?.QUESTION_DELETE); + }; + + const handleEdit = (record: any) => { + setObjectToEdit(record); + navigate(`${ABILITIES_ENUM?.QUESTION}/${record?.id}`); + }; + const [t] = useTranslation(); + + const columns: TableColumnsType = [ + { + title: t("columns.id"), + dataIndex: "id", + key: "id", + align: "center", + render: (text, record) => record?.id, + }, + { + title: `${t("columns.content")}`, + dataIndex: "content", + key: "content", + align: "center", + render: (text, record) => record?.content, + ellipsis: true, + }, + { + title: `${t("columns.hint")}`, + dataIndex: "hint", + key: "hint", + align: "center", + render: (text, record) => { + + return ( + <>{record?.hint ?? "karim"} + ); + }, + ellipsis: true, + }, + { + title: `${t("columns.tags")}`, + dataIndex: "tags", + key: "tags", + align: "center", + + render: (text, record) => { + const tags = record?.tags?.map((item:any)=>{ + return item?.name + }) ?? []; + return ( +
+ {tags.length > 0 ? ( + tags.map((tag, index) => ( + + {tag} + {index < tags.length - 1 && ', '} + + )) + ) : ( + _ + )} +
+ ); + }, + ellipsis: true, + }, + { + title: t("columns.question_type"), + dataIndex: "isBase", + key: "isBase", + align: "center", + render: (text, record) => + record?.isBase ? t("columns.base_question") : t("columns.normal_question"), + }, + + { + title: "#", + key: "actions", + align: "center", + + render: (_text, record, index) => { + return ( + handelDelete(record)} + onEdit={() => handleEdit(record)} + /> + ); + }, + }, + ]; + + return columns; +}; diff --git a/src/Pages/Admin/Report/Page.tsx b/src/Pages/Admin/Report/Page.tsx index 8904c4d..33d9d49 100644 --- a/src/Pages/Admin/Report/Page.tsx +++ b/src/Pages/Admin/Report/Page.tsx @@ -21,9 +21,12 @@ const SearchField = lazy( ); const TableHeader = () => { - const { handel_open_model } = useModalHandler(); const [t] = useTranslation(); - useSetPageTitle(t(`page_header.report`)); + + useSetPageTitle([ + {name:`${t(`page_header.home`)}`, path:"/"}, + {name:`${t(`page_header.report`)}`, path:"report"} + ]); const deleteMutation = useDeleteTag(); return (
diff --git a/src/Pages/Admin/Reseller/Page.tsx b/src/Pages/Admin/Reseller/Page.tsx index 2f3b885..fab96da 100644 --- a/src/Pages/Admin/Reseller/Page.tsx +++ b/src/Pages/Admin/Reseller/Page.tsx @@ -24,7 +24,10 @@ const SearchField = lazy( const TableHeader = () => { const [t] = useTranslation(); - useSetPageTitle(t(`page_header.reseller`)); + useSetPageTitle([ + {name:`${t(`page_header.home`)}`, path:"/"}, + {name:`${t(`page_header.reseller`)}`, path:"reseller"} + ]); const deleteMutation = useDeleteTag(); return (
diff --git a/src/Pages/Admin/Student/Page.tsx b/src/Pages/Admin/Student/Page.tsx index 24693aa..cc7b8a5 100644 --- a/src/Pages/Admin/Student/Page.tsx +++ b/src/Pages/Admin/Student/Page.tsx @@ -20,8 +20,10 @@ const TableHeader = () => { const [t] = useTranslation(); const deleteMutation = useDeleteStudent(); - useSetPageTitle(t(`page_header.student`)); - + useSetPageTitle([ + {name:`${t(`page_header.home`)}`, path:"/"}, + {name:`${t(`page_header.student`)}`, path:"student"} + ]); return (
}> diff --git a/src/Pages/Admin/Tags/Page.tsx b/src/Pages/Admin/Tags/Page.tsx index 116abe5..2b61ec2 100644 --- a/src/Pages/Admin/Tags/Page.tsx +++ b/src/Pages/Admin/Tags/Page.tsx @@ -16,14 +16,15 @@ const EditModalForm = lazy(() => import("./Model/EditModel")); const DeleteModalForm = lazy( () => import("../../../Layout/Dashboard/DeleteModels"), ); -const SearchField = lazy( - () => import("../../../Components/DataTable/SearchField"), -); const TableHeader = () => { - const { handel_open_model } = useModalHandler(); const [t] = useTranslation(); - useSetPageTitle(t(`page_header.tags`)); + + useSetPageTitle([ + {name:`${t(`page_header.home`)}`, path:"/"}, + {name:`${t(`page_header.tags`)}`, path:"tag"} + ]); + const deleteMutation = useDeleteTag(); return (
diff --git a/src/Pages/Admin/Unit/Page.tsx b/src/Pages/Admin/Unit/Page.tsx index f1a312e..9011f94 100644 --- a/src/Pages/Admin/Unit/Page.tsx +++ b/src/Pages/Admin/Unit/Page.tsx @@ -35,15 +35,13 @@ const TableHeader = () => { }); const gradeName = grade?.data?.name ?? ""; - const SubjectName = Subject?.data?.name ?? ""; - useSetPageTitle( - t(`page_header.grade`) + - " / " + - ` ${t("header.subject_of_class")} (${gradeName})` + - " / " + - SubjectName, - ); + useSetPageTitle([ + {name:`${t(`page_header.home`)}`, path:"/"}, + {name:`${t(`page_header.grade`)}`, path:"grade"}, + {name:` ${t("header.subject_of_class")} (${gradeName})`, path:`grade/${grade_id}`}, + {name:SubjectName, path:`subject/${subject_id}`} + ]); return (
diff --git a/src/Pages/Admin/User/Page.tsx b/src/Pages/Admin/User/Page.tsx index fa14056..83a8f2f 100644 --- a/src/Pages/Admin/User/Page.tsx +++ b/src/Pages/Admin/User/Page.tsx @@ -18,7 +18,10 @@ const DeleteModalForm = lazy( const TableHeader = () => { const [t] = useTranslation(); - useSetPageTitle(t(`page_header.user`)); + useSetPageTitle([ + {name:`${t(`page_header.home`)}`, path:"/"}, + {name:`${t(`page_header.user`)}`, path:"user"} + ]); const deleteMutation = useDeleteUser(); return (
diff --git a/src/Pages/Admin/lesson/Page.tsx b/src/Pages/Admin/lesson/Page.tsx index ffc67f3..52f1781 100644 --- a/src/Pages/Admin/lesson/Page.tsx +++ b/src/Pages/Admin/lesson/Page.tsx @@ -26,7 +26,7 @@ const TableHeader = () => { const [t] = useTranslation(); const deleteMutation = useDeleteLesson(); - const { unit_id, curriculum_id, grade_id, subject_id } = + const { unit_id, grade_id, subject_id } = useParams(); const { data: unit } = useGetAllUnit({ show: unit_id }); @@ -41,15 +41,15 @@ const TableHeader = () => { const SubjectName = Subject?.data?.name ?? ""; const unitName = unit?.data?.name ?? ""; - useSetPageTitle( - t(`page_header.grade`) + - " / " + - ` ${t("header.subject_of_class")} (${gradeName})` + - " / " + - SubjectName + - " / " + - unitName, - ); + + useSetPageTitle([ + {name:`${t(`page_header.home`)}`, path:"/"}, + {name:`${t(`page_header.grade`)}`, path:"grade"}, + {name:` ${t("header.subject_of_class")} (${gradeName})`, path:`grade/${grade_id}`}, + {name:SubjectName, path:`subject/${subject_id}`}, + {name:unitName, path:`unit/${unit_id}`} + ]); + return (
diff --git a/src/Pages/Admin/question/AddPage.tsx b/src/Pages/Admin/question/AddPage.tsx index c632a2e..1f4b5dd 100644 --- a/src/Pages/Admin/question/AddPage.tsx +++ b/src/Pages/Admin/question/AddPage.tsx @@ -1,16 +1,15 @@ import React, { Suspense, lazy, useEffect } from "react"; import { Spin } from "antd"; -import FormikForm from "../../../Layout/Dashboard/FormikFormModel"; import { getInitialValues, getValidationSchema, getInitialValuesBase, getValidationSchemaBase, processTags, -} from "./Model/formUtil"; +} from "./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 +18,12 @@ import { Question } from "../../../types/Item"; import BaseForm from "./Model/Malty/Form"; import ModelForm from "./Model/ModelForm"; import { toast } from "react-toastify"; -const AcceptModal = lazy(() => import("./Model/AcceptModal")); +import { Form, Formik } from "formik"; +import { MdOutlineArrowForwardIos } from "react-icons/md"; const AddPage: React.FC = () => { + const location = useLocation(); + const { mutateAsync,isLoading:LoadingAsync } = useAddQuestionAsync(); const { mutate, isLoading, isSuccess } = useAddQuestion(); const { isBseQuestion, setTagsSearch, objectToEdit, setSuccess } = @@ -30,12 +32,7 @@ const AddPage: React.FC = () => { const [t] = useTranslation(); const { subject_id, lesson_id } = useParams(); - 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 +92,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 +108,62 @@ const AddPage: React.FC = () => { } }; + + const handleValidateSingleQuestion = (values:any)=>{ + const haveMoreThanOneAnswer = values?.answers?.length > 1; + const haveOneAnswerRight = haveMoreThanOneAnswer && values?.answers?.some((item:any)=> item?.isCorrect === 1 || item.isCorrect === true ) + 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 + const Loading = LoadingAsync || isLoading; + useEffect(() => { - console.log("all api success"); if (isSuccess) { setSuccess(true); } @@ -137,19 +171,32 @@ const AddPage: React.FC = () => { if (isBseQuestion) { return ( + +
+
+ {t("header.add_new_question")} +
+
- + {({ values,handleSubmit }) => ( + +
{t("practical.back")}
-
-
- }> - - + + )} + +
+
+ ); } + return ( -
- -
-
- -
-
{t("practical.back")}
- -
-
-
- }> - - +
+
{t("practical.back")}
+ +
+ + + )} + + +
); }; diff --git a/src/Pages/Admin/question/EditPage.tsx b/src/Pages/Admin/question/EditPage.tsx index 8535c6c..7c6427c 100644 --- a/src/Pages/Admin/question/EditPage.tsx +++ b/src/Pages/Admin/question/EditPage.tsx @@ -1,13 +1,12 @@ import React, { useEffect } from "react"; import { Modal, Spin } from "antd"; -import FormikForm from "../../../Layout/Dashboard/FormikFormModel"; import { getInitialValues, getValidationSchema, getInitialValuesBase, getValidationSchemaBase, processTags, -} from "./Model/formUtil"; +} from "./formUtil"; import { useAddQuestion, useDeleteQuestion, @@ -25,6 +24,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(); @@ -187,6 +188,56 @@ const EditPage: React.FC = () => { }; + const handleValidateSingleQuestion = (values:any)=>{ + const haveMoreThanOneAnswer = values?.answers?.length > 1; + const haveOneAnswerRight = haveMoreThanOneAnswer && values?.answers?.some((item:any)=> item?.isCorrect === 1 || item.isCorrect === true ) + + 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 +252,24 @@ const EditPage: React.FC = () => { } if (objectToEdit?.isBase) { return ( + + +
+
+ {t("header.edit_question")} +
+
- -
+ {({ values,handleSubmit }) => ( + +
+
{/*
*/}
@@ -218,8 +280,10 @@ const EditPage: React.FC = () => {
{t("practical.back")}
-
- + + )} + + +
); } + return ( + +
+
+ {t("header.edit_question")} +
- -
+ + { + handleSubmit(values); + }} +> + {({ values,handleSubmit }) => ( +
+
{/*
*/}
@@ -252,8 +332,13 @@ const EditPage: React.FC = () => {
{t("practical.back")}
-
- + + + )} +
+
+
+ ); }; diff --git a/src/Pages/Admin/question/Model/AcceptModal.tsx b/src/Pages/Admin/question/Model/AcceptModal.tsx deleted file mode 100644 index 43531b9..0000000 --- a/src/Pages/Admin/question/Model/AcceptModal.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import React from "react"; -import { Modal } from "antd"; -import { useModalState } from "../../../../zustand/Modal"; -import { ModalEnum } from "../../../../enums/Model"; -import { useTranslation } from "react-i18next"; -import { useNavigate } from "react-router-dom"; -import { QUESTION_OBJECT_KEY } from "../../../../config/AppKey"; - -const AcceptModal: React.FC = () => { - const { isOpen, setIsOpen } = useModalState((state) => state); - const navigate = useNavigate(); - - const handleSubmit = () => { - localStorage.removeItem(QUESTION_OBJECT_KEY); - console.log("Handle submit clicked"); - setIsOpen(""); - - navigate(-1); - }; - - const handleCancel = () => { - setIsOpen(""); - }; - - const [t] = useTranslation(); - return ( - <> - -
{t("practical.accept_back")}
- -
-
- -
- -
-
{t("practical.cancel")}
-
{t("practical.accept")}
-
-
-
- - ); -}; - -export default AcceptModal; diff --git a/src/Pages/Admin/question/Model/Field/ChoiceFields.tsx b/src/Pages/Admin/question/Model/Field/ChoiceFields.tsx index 19c7003..552e7eb 100644 --- a/src/Pages/Admin/question/Model/Field/ChoiceFields.tsx +++ b/src/Pages/Admin/question/Model/Field/ChoiceFields.tsx @@ -39,6 +39,7 @@ const ChoiceFields = ({ index, data }: { index: number; data: Choice }) => { name={index} id={`choice_${index + 1}`} type="TextArea" + /> @@ -50,11 +51,11 @@ const ChoiceFields = ({ index, data }: { index: number; data: Choice }) => { name={index} type="Checkbox" /> -

+

{t("header.delete_choice")}

@@ -66,8 +67,10 @@ 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} + autoSize={{ minRows: 2, maxRows: 10 }} />
diff --git a/src/Pages/Admin/question/Model/Field/Choices.tsx b/src/Pages/Admin/question/Model/Field/Choices.tsx index 61f575c..dfe7d95 100644 --- a/src/Pages/Admin/question/Model/Field/Choices.tsx +++ b/src/Pages/Admin/question/Model/Field/Choices.tsx @@ -36,12 +36,21 @@ const Choices = () => { }; return ( - + <> + {formik?.values?.answers?.map((item: Choice, index: number) => { + return ( +
+ +
+ ); + })} + + {/* {(provided) => (
{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 = () => { ); })} - {provided.placeholder} {/* Placeholder for spacing */} + {provided.placeholder}
)}
-
+
*/} + ); }; diff --git a/src/Pages/Admin/question/Model/Malty/ChoiceField/CheckboxField.tsx b/src/Pages/Admin/question/Model/Malty/ChoiceField/CheckboxField.tsx index 990bcdc..139fc2c 100644 --- a/src/Pages/Admin/question/Model/Malty/ChoiceField/CheckboxField.tsx +++ b/src/Pages/Admin/question/Model/Malty/ChoiceField/CheckboxField.tsx @@ -1,7 +1,6 @@ import React from "react"; -import useFormField from "../../../../../../Hooks/useFormField"; -import { Checkbox, Form } from "antd"; -import { useFormik, useFormikContext } from "formik"; +import { Checkbox } from "antd"; +import { useFormikContext } from "formik"; import { useTranslation } from "react-i18next"; const CheckboxField = ({ name, diff --git a/src/Pages/Admin/question/Model/Malty/ChoiceField/ChoiceFields.tsx b/src/Pages/Admin/question/Model/Malty/ChoiceField/ChoiceFields.tsx index eb18b2a..46dac53 100644 --- a/src/Pages/Admin/question/Model/Malty/ChoiceField/ChoiceFields.tsx +++ b/src/Pages/Admin/question/Model/Malty/ChoiceField/ChoiceFields.tsx @@ -6,10 +6,7 @@ import { useTranslation } from "react-i18next"; import { getCharFromNumber } from "../../../../../../utils/getCharFromNumber"; import CheckboxField from "./CheckboxField"; import TextField from "./TextField"; -import File from "./File"; -import { FaTrash } from "react-icons/fa"; import { toast } from "react-toastify"; -import HintField from "./HintField"; import ImageBoxField from "../../../../../../Components/CustomFields/ImageBoxField/ImageBoxField"; import { GoTrash } from "react-icons/go"; @@ -72,11 +69,11 @@ const ChoiceFields = ({ type="Checkbox" parent_index={parent_index} /> -

+

{t("header.delete_choice")}

@@ -89,8 +86,10 @@ 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} + autoSize={{ minRows: 2, maxRows: 10 }} />
diff --git a/src/Pages/Admin/question/Model/Malty/ChoiceField/Choices.tsx b/src/Pages/Admin/question/Model/Malty/ChoiceField/Choices.tsx index d84cd7c..af7cbf9 100644 --- a/src/Pages/Admin/question/Model/Malty/ChoiceField/Choices.tsx +++ b/src/Pages/Admin/question/Model/Malty/ChoiceField/Choices.tsx @@ -44,7 +44,28 @@ const Choices = ({ parent_index }: { parent_index: number }) => { return ( <> - + +
+ {( + (formik?.values as any)?.Questions?.[parent_index]?.answers || + [] + ).map((item: Choice, index: number) => { + return ( +
+ +
+ ); + })} + +
+ {/* {(provided) => (
@@ -87,7 +108,7 @@ const Choices = ({ parent_index }: { parent_index: number }) => {
)}
-
+
*/} ); }; diff --git a/src/Pages/Admin/question/Model/Malty/ChoiceField/File.tsx b/src/Pages/Admin/question/Model/Malty/ChoiceField/File.tsx deleted file mode 100644 index b3d2e37..0000000 --- a/src/Pages/Admin/question/Model/Malty/ChoiceField/File.tsx +++ /dev/null @@ -1,88 +0,0 @@ -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}].answers[${name}].answer_image`; - - const { formik, t, isError, errorMsg } = useFormField(newName, props); - let imageUrl = - formik?.values?.Questions?.[parent_index]?.answers[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}].answers[${name}].answer_image`, - value?.file?.originFileObj, - ); - } - }; - const customRequest = async ({ onSuccess, no_label, label_icon }: any) => { - onSuccess(); - }; - return ( -
- - - - -
{isError ? "required" : ""}
- {errorMsg} -
-
- ); -}; - -export default File; diff --git a/src/Pages/Admin/question/Model/Malty/ChoiceField/HintField.tsx b/src/Pages/Admin/question/Model/Malty/ChoiceField/HintField.tsx deleted file mode 100644 index dcdf284..0000000 --- a/src/Pages/Admin/question/Model/Malty/ChoiceField/HintField.tsx +++ /dev/null @@ -1,54 +0,0 @@ -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 HintField = ({ - name, - label, - label2, - placeholder, - isDisabled, - onChange, - props, - parent_index, - id, - className, -}: any) => { - const newName = `Questions[${parent_index}].answers[${name}].hint`; - - const { formik, isError, errorMsg, t } = useFormField(newName, props); - const TextFilehandleChange = ( - e: React.ChangeEvent, - ) => { - // console.log('Change:', e.target.value); - formik.setFieldValue(newName, e.target.value); - }; - - return ( -
- - - - -
- ); -}; - -export default React.memo(HintField); diff --git a/src/Pages/Admin/question/Model/Malty/Form.tsx b/src/Pages/Admin/question/Model/Malty/Form.tsx index bad59e2..8effc15 100644 --- a/src/Pages/Admin/question/Model/Malty/Form.tsx +++ b/src/Pages/Admin/question/Model/Malty/Form.tsx @@ -86,6 +86,14 @@ const Form = () => { }, ); + + useEffect(() => { + if (Success) { + formik.resetForm() + setSuccess(false); + } + }, [Success]); + return (
@@ -99,7 +107,7 @@ const Form = () => {
-
+
{((formik?.values as any)?.Questions || [])?.map( (item: Choice, parent_index: number) => { @@ -132,8 +140,10 @@ 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" }} + autoSize={{ minRows: 2, maxRows: 10 }} + showCount={false} />
diff --git a/src/Pages/Admin/question/Model/Malty/QuestionFIeld/File.tsx b/src/Pages/Admin/question/Model/Malty/QuestionFIeld/File.tsx deleted file mode 100644 index fdc5bab..0000000 --- a/src/Pages/Admin/question/Model/Malty/QuestionFIeld/File.tsx +++ /dev/null @@ -1,85 +0,0 @@ -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 ( -
- - - - -
{isError ? "required" : ""}
- {errorMsg} -
-
- ); -}; - -export default File; diff --git a/src/Pages/Admin/question/Model/Malty/QuestionFIeld/HintField.tsx b/src/Pages/Admin/question/Model/Malty/QuestionFIeld/HintField.tsx deleted file mode 100644 index 753a8b3..0000000 --- a/src/Pages/Admin/question/Model/Malty/QuestionFIeld/HintField.tsx +++ /dev/null @@ -1,52 +0,0 @@ -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 HintField = ({ - name, - label, - label2, - placeholder, - isDisabled, - onChange, - props, - id, - className, -}: any) => { - const newName = `Questions[${name}].hint`; - const { formik, isError, errorMsg, t } = useFormField(newName, props); - const TextFilehandleChange = ( - e: React.ChangeEvent, - ) => { - // console.log('Change:', e.target.value); - formik.setFieldValue(newName, e.target.value); - }; - - return ( -
- - - - -
- ); -}; - -export default React.memo(HintField); diff --git a/src/Pages/Admin/question/Model/Malty/QuestionFIeld/QuestionFIeld.tsx b/src/Pages/Admin/question/Model/Malty/QuestionFIeld/QuestionFIeld.tsx index a4ccdd6..907b975 100644 --- a/src/Pages/Admin/question/Model/Malty/QuestionFIeld/QuestionFIeld.tsx +++ b/src/Pages/Admin/question/Model/Malty/QuestionFIeld/QuestionFIeld.tsx @@ -1,16 +1,10 @@ import React, { useEffect } 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"; -import { FaTrash } from "react-icons/fa"; import { useObjectToEdit } from "../../../../../../zustand/ObjectToEditState"; -import { toast } from "react-toastify"; -import CheckboxField from "./CheckboxField"; -import HintField from "./HintField"; import ImageBoxField from "../../../../../../Components/CustomFields/ImageBoxField/ImageBoxField"; import { GoTrash } from "react-icons/go"; @@ -53,12 +47,12 @@ const QuestionFIeld = ({ index, data }: { index: number; data: Choice }) => { -
+

{t("header.delete_question")}

diff --git a/src/Pages/Admin/question/Model/Malty/Tags/DynamicTags.tsx b/src/Pages/Admin/question/Model/Malty/Tags/DynamicTags.tsx deleted file mode 100644 index 81b5fd8..0000000 --- a/src/Pages/Admin/question/Model/Malty/Tags/DynamicTags.tsx +++ /dev/null @@ -1,107 +0,0 @@ -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(); - const [t] = useTranslation(); - const { TagsSearch, setTagsSearch, currentTag, currentParentIndex } = - useObjectToEdit(); - const { data } = useGetAllTag({ - name: TagsSearch, - }); - 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; - setTagsSearch(null); - - 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?.Questions?.[parent_index]?.tags?.length; - console.log(currentTag); - - formik.setFieldValue(`Questions.[${parent_index}].tags[${currentTag}]`, { - ...item, - key: length, - }); - setTagsSearch(null); - }; - - // console.log(formik?.values?.tags?.length); - - return ( -
- {formik?.values?.Questions?.[parent_index]?.tags?.length < 1 && ( -

- {" "} - {t("header.add_tag")} -

- )} - -
-
- {( - ((formik?.values as any)?.Questions?.[parent_index] - ?.tags as any[]) || [] - ).map((item: any, index: number) => { - return ( - - ); - })} -
- - {formik?.values?.Questions?.[parent_index]?.tags?.length > 0 && ( -

- -

- )} -
- {TagsSearch && currentParentIndex === parent_index && ( -
- {suggests?.map((item: any, index: number) => { - console.log(currentParentIndex === parent_index); - - return ( -
handleChoice(item)} - > - {item?.name} -
- ); - })} -
- )} -
- ); -}; - -export default DynamicTags; diff --git a/src/Pages/Admin/question/Model/Malty/Tags/MaltySelectTag.tsx b/src/Pages/Admin/question/Model/Malty/Tags/MaltySelectTag.tsx index 18026d3..e140d88 100644 --- a/src/Pages/Admin/question/Model/Malty/Tags/MaltySelectTag.tsx +++ b/src/Pages/Admin/question/Model/Malty/Tags/MaltySelectTag.tsx @@ -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]; diff --git a/src/Pages/Admin/question/Model/Malty/Tags/Tag.tsx b/src/Pages/Admin/question/Model/Malty/Tags/Tag.tsx deleted file mode 100644 index fbbfcd0..0000000 --- a/src/Pages/Admin/question/Model/Malty/Tags/Tag.tsx +++ /dev/null @@ -1,80 +0,0 @@ -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(null); - const timeoutRef = useRef(null); - const DEBOUNCE_DELAY = 500; - const formik = useFormikContext(); - const { setTagsSearch, setCurrentTag, setCurrentParentIndex } = - useObjectToEdit(); - console.log(formik?.values?.Questions); - - 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) => { - // console.log(e.target.value); - - formik.setFieldValue(`Questions.[${parent_index}].tags[${index}]`, { - key: parent_index, - name: e.target.value, - id: `${parent_index}_key`, - }); - setCurrentTag(index); - setCurrentParentIndex(parent_index); - if (timeoutRef.current) { - clearTimeout(timeoutRef.current); - } - - timeoutRef.current = setTimeout(() => { - setTagsSearch(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 - setTagsSearch(null); - }; - - return ( -
- - -
- ); -}; - -export default Tag; diff --git a/src/Pages/Admin/question/Model/ModelForm.tsx b/src/Pages/Admin/question/Model/ModelForm.tsx index 483e1d8..6de101f 100644 --- a/src/Pages/Admin/question/Model/ModelForm.tsx +++ b/src/Pages/Admin/question/Model/ModelForm.tsx @@ -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 (
@@ -62,7 +61,7 @@ const Form = () => {
- {formik?.values?.answers?.length < 5 && ( + {(formik?.values?.answers === null || formik?.values?.answers === undefined || formik?.values?.answers?.length < 5) && (

handleAddChoice()} size={23} />{" "} {t("header.add_new_choice")} @@ -75,8 +74,11 @@ const Form = () => { placeholder="_" name="hint" label="hint_question" - type="text" - style={{ width: "100%" }} + type="TextArea" + style={{ width: "100%" , height: 60,resize:"none" }} + showCount={false} + autoSize={{ minRows: 2, maxRows: 10 }} + />

diff --git a/src/Pages/Admin/question/Page.tsx b/src/Pages/Admin/question/Page.tsx index cc5d70f..6584a49 100644 --- a/src/Pages/Admin/question/Page.tsx +++ b/src/Pages/Admin/question/Page.tsx @@ -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"; @@ -43,17 +42,15 @@ const TableHeader = () => { const unitName = unit?.data?.name ?? ""; const LessonName = Lesson?.data?.name ?? ""; - useSetPageTitle( - t(`page_header.grade`) + - " / " + - ` ${t("header.subject_of_class")} (${gradeName})` + - " / " + - SubjectName + - " / " + - unitName + - " / " + - LessonName, - ); + useSetPageTitle([ + {name:`${t(`page_header.home`)}`, path:"/"}, + {name:`${t(`page_header.grade`)}`, path:"grade"}, + {name:` ${t("header.subject_of_class")} (${gradeName})`, path:`grade/${grade_id}`}, + {name:SubjectName, path:`subject/${subject_id}`}, + {name:unitName, path:`unit/${unit_id}`}, + {name:LessonName, path:`lesson/${lesson_id }`} + ]); + return (
diff --git a/src/Pages/Admin/question/Table.tsx b/src/Pages/Admin/question/Table.tsx index 94eae88..491377b 100644 --- a/src/Pages/Admin/question/Table.tsx +++ b/src/Pages/Admin/question/Table.tsx @@ -11,7 +11,7 @@ const App: React.FC = () => { const { filterState } = useFilterState(); const response = useGetAllQuestion({ - lesson_id: lesson_id, + lessonsIds: [lesson_id], pagination: true, ...filterState, }); diff --git a/src/Pages/Admin/question/Model/formUtil.ts b/src/Pages/Admin/question/formUtil.ts similarity index 84% rename from src/Pages/Admin/question/Model/formUtil.ts rename to src/Pages/Admin/question/formUtil.ts index 85d1cd9..1a4f553 100644 --- a/src/Pages/Admin/question/Model/formUtil.ts +++ b/src/Pages/Admin/question/formUtil.ts @@ -1,12 +1,12 @@ import * as Yup from "yup"; -import { Question } from "../../../../types/Item"; +import { Question } from "../../../types/Item"; import { toast } from "react-toastify"; export const getInitialValues = (objectToEdit: Question): any => { const tags = objectToEdit?.tags?.map((item: any, index: number) => { return { ...item }; }); - + return { id: objectToEdit?.id ?? null, content: objectToEdit?.content ?? "", @@ -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,15 @@ 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) => { + return answers?.some( + (answer: any) => + answer?.isCorrect === true || answer?.isCorrect === 1, + ); + }, ), }); }; @@ -42,10 +51,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 +70,7 @@ export const getInitialValuesBase = (objectToEdit: Question): any => { }; }); - const questions = newQuestions ?? []; + const questions = newQuestions ?? [{answers:[]}]; return { id: objectToEdit?.id ?? null, @@ -84,13 +101,12 @@ 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"); - + return answers.some( (answer: any) => answer.isCorrect === true || answer.isCorrect === 1, @@ -98,7 +114,7 @@ export const getValidationSchemaBase = () => { }, ), }), - ), + ).min(1), }); }; diff --git a/src/Pages/Admin/question/useTableColumns.tsx b/src/Pages/Admin/question/useTableColumns.tsx index da5680c..1c2e4bc 100644 --- a/src/Pages/Admin/question/useTableColumns.tsx +++ b/src/Pages/Admin/question/useTableColumns.tsx @@ -45,19 +45,59 @@ export const useColumns = () => { }, { title: `${t("columns.content")}`, - dataIndex: "name", - key: "name", + dataIndex: "content", + key: "content", align: "center", render: (text, record) => record?.content, ellipsis: true, }, { - title: t("columns.isBase"), + title: `${t("columns.hint")}`, + dataIndex: "hint", + key: "hint", + align: "center", + render: (text, record) => { + + return ( + <>{record?.hint ?? "_"} + ); + }, + ellipsis: true, + }, + { + title: `${t("columns.tags")}`, + dataIndex: "tags", + key: "tags", + align: "center", + + render: (text, record) => { + const tags = record?.tags?.map((item:any)=>{ + return item?.name + }) ?? []; + return ( +
+ {tags.length > 0 ? ( + tags.map((tag, index) => ( + + {tag} + {index < tags.length - 1 && ', '} + + )) + ) : ( + _ + )} +
+ ); + }, + ellipsis: true, + }, + { + title: t("columns.question_type"), dataIndex: "isBase", key: "isBase", align: "center", render: (text, record) => - record?.isBase ? t("practical.yes") : t("practical.no"), + record?.isBase ? t("columns.base_question") : t("columns.normal_question"), }, { diff --git a/src/Pages/Admin/subject/Table/Page.tsx b/src/Pages/Admin/subject/Table/Page.tsx index 5eb9789..03addb0 100644 --- a/src/Pages/Admin/subject/Table/Page.tsx +++ b/src/Pages/Admin/subject/Table/Page.tsx @@ -32,11 +32,15 @@ const TableWithHeader = () => { }); const gradeName = grade?.data?.name ?? ""; - useSetPageTitle( - t(`page_header.grade`) + - " / " + - ` ${t("header.subject_of_class")} (${gradeName})`, - ); + + + useSetPageTitle([ + {name:`${t(`page_header.home`)}`, path:"/"}, + {name:`${t(`page_header.grade`)}`, path:"grade"}, + {name:` ${t("header.subject_of_class")} (${gradeName})`, path:`grade/${grade_id}`} + ]); + + return (
diff --git a/src/Pages/Auth/FormField.tsx b/src/Pages/Auth/FormField.tsx index 00181ca..50ba4f1 100644 --- a/src/Pages/Auth/FormField.tsx +++ b/src/Pages/Auth/FormField.tsx @@ -1,19 +1,7 @@ -import React, { useEffect, useState } from "react"; -import { Form, Field, useFormikContext } from "formik"; -import Image from "../../Components/Ui/Image"; -import { Input } from "antd"; -import AuthSelect from "../../Components/Ui/Custom/AuthSelect"; -// import { useGetAllCycle } from "../../api/cycle"; -// import { useGetAllBranch } from "../../api/branch"; -import { useGetAllTerm } from "../../api/term"; -import { FormValues } from "../../types/Auth"; -import { - BRANCH_OBJECT_KEY, - CYCLE_OBJECT_KEY, - TERM_OBJECT_KEY, -} from "../../config/AppKey"; -import useFormatAuthDataToSelect from "../../utils/useFormatAuthDataToSelect"; +import { Form, useFormikContext } from "formik"; + import { useTranslation } from "react-i18next"; +import ValidationField from "../../Components/ValidationField/ValidationField"; type FormFieldType = { isLoading: boolean; @@ -21,26 +9,18 @@ type FormFieldType = { const FormField = ({ isLoading }: FormFieldType) => { const [t] = useTranslation(); + const {isValid} = useFormikContext(); + console.log(isValid,"isValid"); + return (
{/* */}

{t("تسجيل الدخول إلى حسابك")}

-
- - -
-
+ + + + {/*
@@ -53,9 +33,9 @@ const FormField = ({ isLoading }: FormFieldType) => { className="passwordInput" size="large" /> -
+
*/} - diff --git a/src/Pages/Auth/LoginForm.tsx b/src/Pages/Auth/LoginForm.tsx index 8b63fa9..ffbcbf8 100644 --- a/src/Pages/Auth/LoginForm.tsx +++ b/src/Pages/Auth/LoginForm.tsx @@ -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 (
- + {(formikProps) => }
diff --git a/src/Pages/Auth/formutils.ts b/src/Pages/Auth/formutils.ts index bd6faa1..11f0799 100644 --- a/src/Pages/Auth/formutils.ts +++ b/src/Pages/Auth/formutils.ts @@ -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 = { diff --git a/src/Pages/Home/Dummy.tsx b/src/Pages/Home/Dummy.tsx index 85181c8..0776ba5 100644 --- a/src/Pages/Home/Dummy.tsx +++ b/src/Pages/Home/Dummy.tsx @@ -3,6 +3,8 @@ 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"; +import PageTitle from "../../Layout/Dashboard/PageTitle"; const Dummy = () => { const [t] = useTranslation(); @@ -10,8 +12,8 @@ const Dummy = () => { const { FilterButton, FilterBody } = useFilter(); return (
- {/* - karim */} + +
); }; diff --git a/src/Routes.tsx b/src/Routes.tsx index c390885..ccb0641 100644 --- a/src/Routes.tsx +++ b/src/Routes.tsx @@ -1,5 +1,5 @@ import { TCrudRoute, TMenuItem } from "./types/App"; -import { FaHome, FaMoneyBill, FaSellcast } from "react-icons/fa"; +import { FaCashRegister, FaHome, FaMoneyBill, FaPaperclip, FaSellcast, FaTag, FaUser } from "react-icons/fa"; import React from "react"; const Dummy = React.lazy(() => import("./Pages/Home/Dummy")); @@ -33,6 +33,7 @@ const EditReSeller = React.lazy( const User = React.lazy(() => import("./Pages/Admin/User/Page")); const Param = React.lazy(() => import("./Pages/Admin/Param/Page")); +const QuestionBank = React.lazy(() => import("./Pages/Admin/QuestionBank/Page")); /// RESELLER /// const Student_Package = React.lazy( @@ -44,12 +45,14 @@ import { ABILITIES_ENUM, ABILITIES_VALUES_ENUM } from "./enums/abilities"; import { ParamsEnum } from "./enums/params"; import { TbCategory } from "react-icons/tb"; import { UserTypeEnum } from "./enums/UserType"; +import { FaTags } from "react-icons/fa6"; +import { MdGrade } from "react-icons/md"; export const menuItems: TMenuItem[] = [ { header: "page_header.dashboard", element: , - icon: , + icon: , text: "sidebar.dashboard", path: "/", abilities: ABILITIES_ENUM?.PASS, @@ -60,7 +63,7 @@ export const menuItems: TMenuItem[] = [ { header: "page_header.grade", element: , - icon: , + icon: , text: "sidebar.grade", path: `/${ABILITIES_ENUM?.GRADE}`, abilities: ABILITIES_ENUM?.GRADE, @@ -70,7 +73,7 @@ export const menuItems: TMenuItem[] = [ { header: "page_header.tags", element: , - icon: , + icon: , text: "sidebar.tags", path: `/${ABILITIES_ENUM?.TAG}`, abilities: ABILITIES_ENUM?.TAG, @@ -78,9 +81,9 @@ export const menuItems: TMenuItem[] = [ prevPath: 0, }, { - header: "page_header.tags", + header: "page_header.report", element: , - icon: , + icon: , text: "sidebar.report", path: `/${ABILITIES_ENUM?.Report}`, abilities: ABILITIES_ENUM?.Report, @@ -90,7 +93,7 @@ export const menuItems: TMenuItem[] = [ { header: "page_header.student", element: , - icon: , + icon: , text: "sidebar.student", path: `/${ABILITIES_ENUM?.STUDENT}`, abilities: ABILITIES_ENUM?.STUDENT, @@ -100,7 +103,7 @@ export const menuItems: TMenuItem[] = [ { header: "page_header.reSeller", element: , - icon: , + icon: , text: "sidebar.reseller", path: `/${ABILITIES_ENUM?.RE_SELLER}`, abilities: ABILITIES_ENUM?.RE_SELLER, @@ -110,7 +113,7 @@ export const menuItems: TMenuItem[] = [ { header: "page_header.user", element: , - icon: , + icon: , text: "sidebar.user", path: `/${ABILITIES_ENUM?.USER}`, abilities: ABILITIES_ENUM?.USER, @@ -128,6 +131,18 @@ export const menuItems: TMenuItem[] = [ prevPath: 0, }, + { + header: "page_header.questionBank", + element: , + icon: , + text: "sidebar.questionBank", + path: `/${ABILITIES_ENUM?.QUESTION}`, + abilities: ABILITIES_ENUM?.QUESTION, + abilities_value: ABILITIES_VALUES_ENUM.INDEX, + prevPath: 0, + }, + + /// RESELLER ///// { diff --git a/src/Styles/Antd/Mix.scss b/src/Styles/Antd/Mix.scss index 1f327c6..eaf8c3e 100644 --- a/src/Styles/Antd/Mix.scss +++ b/src/Styles/Antd/Mix.scss @@ -10,12 +10,7 @@ } } } - -.Popover { - .ant-popover-inner { - padding: 0 !important; - } -} +x .Color_type_checkbox.false { .ant-checkbox-checked .ant-checkbox-inner { diff --git a/src/Styles/Layout/PageHeader.scss b/src/Styles/Layout/PageHeader.scss index e276dba..4368f36 100644 --- a/src/Styles/Layout/PageHeader.scss +++ b/src/Styles/Layout/PageHeader.scss @@ -9,6 +9,9 @@ } .page_links { color: var(--opacity); + display: flex; + align-items: center; + gap: 10px; } } } @@ -16,3 +19,12 @@ .filter_header_top { color: #202c4b; } + + +.PageTitle{ + display: flex; + gap: 10px; + .PageTitleItems{ + cursor: pointer; + } +} \ No newline at end of file diff --git a/src/Styles/Pages/exercise.scss b/src/Styles/Pages/exercise.scss index e26731e..2ba2a34 100644 --- a/src/Styles/Pages/exercise.scss +++ b/src/Styles/Pages/exercise.scss @@ -41,7 +41,7 @@ // padding: 2vw; .exercise_add_main { background: var(--bg); - padding: 2vw; + padding: 10px 2vw; } .exercise_add_buttons { display: flex; @@ -127,12 +127,14 @@ display: flex; justify-content: space-between; width: 100%; - padding: 14px 10px; + padding: 14px 20px; background: #f2f4f8; border-radius: 10px 10px 0 0; margin: 0 !important; box-shadow: 0px 0px 4px 2px rgba(0, 0, 0, 0.1); - + div{ + margin-left: 25px; + } img { cursor: pointer; } @@ -144,7 +146,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 +214,44 @@ 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; + } +} + +.SelectTag{ + label{ + font-weight: bold; + font-size: 19px; + } +} \ No newline at end of file diff --git a/src/api/auth.ts b/src/api/auth.ts index 16d5a99..b29bbe4 100644 --- a/src/api/auth.ts +++ b/src/api/auth.ts @@ -5,4 +5,4 @@ const API = { LOGIN: `login`, LOGOUT: `logout`, }; -export const useLoginAdmin = () => useAddMutation(KEY, API.LOGIN, false); +export const useLoginAdmin = () => useAddMutation(KEY, API.LOGIN, true); diff --git a/src/api/helper/useAxios.ts b/src/api/helper/useAxios.ts index b2f39fc..69da961 100644 --- a/src/api/helper/useAxios.ts +++ b/src/api/helper/useAxios.ts @@ -50,6 +50,8 @@ function useAxios() { return response; }, function (error) { + console.log(error?.response); + const status = error?.request?.status; const errorMsg = error?.response?.data?.message; const errorField = error?.response?.data; diff --git a/src/enums/Model.ts b/src/enums/Model.ts index 5a95bef..de37336 100644 --- a/src/enums/Model.ts +++ b/src/enums/Model.ts @@ -186,4 +186,11 @@ export enum ModalEnum { Student_Package_EDIT = "Student_Package.edit", Student_Package_ADD = "Student_Package.add", Student_Package_DELETE = "Student_Package.delete", + + + ///QuestionBank + + QUESTION_BANK_ADD = "QuestionBank.add", + QUESTION_BANK_EDIT = "QuestionBank.edit", + QUESTION_BANK_DELETE = "QuestionBank.delete", } diff --git a/src/enums/abilities.ts b/src/enums/abilities.ts index 427f62a..e84627a 100644 --- a/src/enums/abilities.ts +++ b/src/enums/abilities.ts @@ -47,6 +47,7 @@ export enum ABILITIES_ENUM { User = "user", RE_SELLER = "reseller", Student_Package = "student_package", + QUESTION_BANK = "QuestionBank" //// } diff --git a/src/translate/ar.json b/src/translate/ar.json index e264634..81c2b58 100644 --- a/src/translate/ar.json +++ b/src/translate/ar.json @@ -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": "الرقم التعريفي", @@ -183,7 +187,12 @@ "subject":"المادة", "quiz_status":"حالة الاختبار", "creator_name":"اسم المنشئ", - "created_by":"أنشئ بواسطة" + "created_by":"أنشئ بواسطة", + "question_type": "نوع تمرين", + "base_question": " تمرين متعدد ", + "normal_question": " تمرين عادي", + "hint":"شرح ", + "tags":"كلمات مفتاحية" }, "practical": { "to_confirm_deletion_please_re_enter": "لتأكيد الحذف، يرجى إعادة الإدخال", @@ -749,7 +758,8 @@ "reseller": "البائعين", "param": "معامل", "student_package": "حزمة الطالب", - "quiz":"الاختبارات" + "quiz":"الاختبارات", + "questionBank":"بنك الأسئلة" }, "message": { "some_thing_went_wrong": "حدث خطأ ما", @@ -784,17 +794,18 @@ "grade": "الصفوف", "report": "تقرير", "tags": "كلمات مفتاحية", - "reseller":"البائعين" + "reseller":"البائعين", + "QuestionBank":"بنك الأسئلة" }, "page_header": { - "dashboard": "لوحة القيادة / الصفحة الرئيسية", - "course": " لوحة القيادة / الصفوف ", - "teacher": " لوحة القيادة / المعلمون", - "payment": " لوحة القيادة / الدفعات", - "branch": " لوحة القيادة / الفروع", - "role": " لوحة القيادة / الادوار", - "student": " لوحة القيادة / قائمة الطلاب ", - "admin": " لوحة القيادة / المسؤولون", + "home": "لوحة القيادة", + "course": " الصفوف ", + "teacher": " المعلمون", + "payment": " الدفعات", + "branch": " الفروع", + "role": " الادوار", + "student": " قائمة الطلاب ", + "admin": " المسؤولون", "student_details": "تفاصيل الطالب", "create_student": "إنشاء طالب", "course_details": "تفاصيل الصف", @@ -802,32 +813,34 @@ "student_payment": "دفع الطالب", "student_note": "ملاحظات الطالب", "student_status": "حالة الطالب", - "education_class": "لوحة القيادة / الصفوف / الشعب", - "education_class_details": " لوحة القيادة / الصفوف / الشعب / تفاصيل الشعبة", - "subject_details": " لوحة القيادة / تفاصيل المادة ", - "cycle": "لوحة القيادة / السنة دراسية ", - "term": "لوحة القيادة / الفصل ", - "unit_details": "لوحة القيادة / تفاصيل المادة / تفاصيل الوحدة", - "lesson_details": "لوحة القيادة / تفاصيل المادة / تفاصيل الوحدة / تفاصيل الدرس", - "exercise_add": "لوحة القيادة / تفاصيل الدرس / إضافة تمارين ", - "subject": "لوحة القيادة / المادة", - "tags": "لوحة القيادة / كلمات مفتاحية", - "Question": "لوحة القيادة /اسئلة ", - "add_Question": "لوحة القيادة /إضافة اسئلة ", - "edit_Question": "لوحة القيادة /تعديل اسئلة ", - "grade": "لوحة القيادة / الصفوف", + "education_class": "الصفوف / الشعب", + "education_class_details": " الصفوف / الشعب / تفاصيل الشعبة", + "subject_details": " تفاصيل المادة ", + "cycle": " السنة دراسية ", + "term": "الفصل ", + "unit_details": "تفاصيل المادة / تفاصيل الوحدة", + "lesson_details": "تفاصيل المادة / تفاصيل الوحدة / تفاصيل الدرس", + "exercise_add": "تفاصيل الدرس / إضافة تمارين ", + "subject": "المادة", + "tags": "كلمات مفتاحية", + "Question": "سئلة ", + "add_Question": "ضافة اسئلة ", + "edit_Question": "عديل اسئلة ", + "grade": "الصفوف", "report": "تقرير", - "users": "لوحة القيادة / المستخدمون", - "reseller": " لوحة القيادة / البائعين", - "add_reseller": " لوحة القيادة / البائعين / إضافة بائع ", + "users": "المستخدمون", + "reseller": " البائعين", + "add_reseller": " البائعين / إضافة بائع ", "param": "معامل", - "student_package": "حزمة الطالب" + "student_package": "حزمة الطالب", + "QuestionBank":"بنك الأسئلة" }, "table": { "student": "قائمة الطلاب", "reseller": "البائعين", "grade": "قائمة الصفوف", - "subjects": "مواد الصف" + "subjects": "مواد الصف", + "QuestionBank":"بنك الأسئلة" }, "alphabet": { "A": "A", diff --git a/src/utils/hasAbilityFn.ts b/src/utils/hasAbilityFn.ts index 221883b..dc4e751 100644 --- a/src/utils/hasAbilityFn.ts +++ b/src/utils/hasAbilityFn.ts @@ -677,3 +677,25 @@ export const canDeleteStudent_Package = hasAbility( ); + + +/// QuestionBank + +export const canAddQuestionBank = hasAbility( + ABILITIES_ENUM.QUESTION_BANK, + ABILITIES_VALUES_ENUM.STORE, +); + +export const canEditQuestionBank = hasAbility( + ABILITIES_ENUM.QUESTION_BANK, + ABILITIES_VALUES_ENUM.UPDATE, +); +export const canDeleteQuestionBank = hasAbility( + ABILITIES_ENUM.QUESTION_BANK, + ABILITIES_VALUES_ENUM.DELETE, +); + +export const canShowQuestionBank = hasAbility( + ABILITIES_ENUM.QUESTION_BANK, + ABILITIES_VALUES_ENUM.SHOW, +);