add filter
This commit is contained in:
parent
c1e2718e14
commit
c08de08790
|
|
@ -2,6 +2,8 @@ import React, { useState, useEffect, useRef } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { IoSearch } from "react-icons/io5";
|
import { IoSearch } from "react-icons/io5";
|
||||||
import { useLocation, useNavigate } from "react-router-dom";
|
import { useLocation, useNavigate } from "react-router-dom";
|
||||||
|
import { useFilterStateState } from "../../zustand/Filter";
|
||||||
|
import { useDebounce } from "../../utils/useDebounce";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
placeholder: string;
|
placeholder: string;
|
||||||
|
|
@ -11,36 +13,25 @@ interface Props {
|
||||||
const SearchField: React.FC<Props> = ({ placeholder, searchBy }) => {
|
const SearchField: React.FC<Props> = ({ placeholder, searchBy }) => {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const [searchQuery, setSearchQuery] = useState<string>("");
|
const [searchQuery, setSearchQuery] = useState<string>("");
|
||||||
const location = useLocation();
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
|
||||||
|
|
||||||
const DEBOUNCE_DELAY = 500; // Adjust the debounce delay as needed
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const searchParams = new URLSearchParams(location.search);
|
const {setFilter} = useFilterStateState()
|
||||||
setSearchQuery(searchParams.get(searchBy) || "");
|
|
||||||
}, [location.search, searchBy]);
|
|
||||||
|
|
||||||
const handleInputChange = (value: string) => {
|
const handleInputChange = (value: string) => {
|
||||||
setSearchQuery(value);
|
setSearchQuery(value);
|
||||||
|
|
||||||
if (timeoutRef.current) {
|
|
||||||
clearTimeout(timeoutRef.current);
|
|
||||||
}
|
|
||||||
|
|
||||||
timeoutRef.current = setTimeout(() => {
|
|
||||||
if (value.trim() !== "") {
|
|
||||||
navigate(`${location.pathname}?${searchBy}=${value.trim()}`);
|
|
||||||
} else {
|
|
||||||
const params = new URLSearchParams(location.search);
|
|
||||||
params.delete(searchBy);
|
|
||||||
navigate(`${location.pathname}`);
|
|
||||||
}
|
|
||||||
}, DEBOUNCE_DELAY);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleInputChangeWithDebounce = useDebounce(
|
||||||
|
(value: string) => {
|
||||||
|
setFilter({
|
||||||
|
name:value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
const handleToggleDropdown = () => {
|
const handleToggleDropdown = () => {
|
||||||
setIsOpen(!isOpen);
|
setIsOpen(!isOpen);
|
||||||
};
|
};
|
||||||
|
|
@ -69,7 +60,7 @@ const SearchField: React.FC<Props> = ({ placeholder, searchBy }) => {
|
||||||
className="search__input"
|
className="search__input"
|
||||||
placeholder={t(placeholder)}
|
placeholder={t(placeholder)}
|
||||||
value={searchQuery}
|
value={searchQuery}
|
||||||
onChange={(e) => handleInputChange(e.target.value)}
|
onChange={(e) => {handleInputChange(e.target.value) ; handleInputChangeWithDebounce(e.target.value)}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,54 +1,36 @@
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Divider, Select } from "antd";
|
import { Divider, Select } from "antd";
|
||||||
import SearchFieldWithSelect from "../../Components/DataTable/SearchFieldWithSelect";
|
|
||||||
import { translateOptions } from "../../utils/translatedOptions";
|
|
||||||
import { search_array } from "../../Routes";
|
|
||||||
import { useFilterStateState } from "../../zustand/Filter";
|
|
||||||
import { useSearchParams } from "react-router-dom";
|
|
||||||
import { TbReorder } from "react-icons/tb";
|
import { TbReorder } from "react-icons/tb";
|
||||||
|
import { useFilterStateState } from "../../zustand/Filter";
|
||||||
|
|
||||||
const OrderBySelect = () => {
|
const OrderBySelect = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { Filter, setFilter } = useFilterStateState();
|
const {setFilter} = useFilterStateState()
|
||||||
const [searchParams, setSearchParams] = useSearchParams();
|
|
||||||
|
|
||||||
const type_param = searchParams.get("type");
|
|
||||||
const [type, setType] = useState(type_param);
|
|
||||||
const translateArray = translateOptions(search_array, t);
|
|
||||||
const handleChange = (value: string) => {
|
const handleChange = (value: string) => {
|
||||||
const newArray = Filter?.filter((item: any) => item.select !== true);
|
setFilter({
|
||||||
setFilter([
|
sort_by:value
|
||||||
...newArray,
|
})
|
||||||
{ name: value, index: Filter.length, select: true },
|
|
||||||
]);
|
|
||||||
if (type_param) {
|
|
||||||
searchParams.delete("type");
|
|
||||||
setSearchParams(searchParams);
|
|
||||||
}
|
|
||||||
setType(value);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// send this with api request
|
|
||||||
// type: type,
|
|
||||||
// page: currentPage,
|
|
||||||
return (
|
return (
|
||||||
<div className="order_by_filter">
|
<div className="order_by_filter">
|
||||||
<Select
|
<Select
|
||||||
className="order_by_select"
|
className="order_by_select"
|
||||||
style={{ width: 200 }}
|
style={{ width: 200 }}
|
||||||
size="large"
|
size="large"
|
||||||
|
allowClear
|
||||||
placeholder={
|
placeholder={
|
||||||
<div>
|
<div>
|
||||||
<TbReorder className="addition_select_icon" /> {t("ترتيب حسب")}{" "}
|
<TbReorder className="addition_select_icon" /> {t("header.sort_by")}{" "}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
options={[
|
options={[
|
||||||
{ value: "تصاعديا", label: t("تصاعديا") },
|
{ value: "ascending", label: t("select.array.order.ascending") },
|
||||||
{ value: "تنازليا", label: t("تنازليا") },
|
{ value: "descending", label: t("select.array.order.descending") },
|
||||||
{ value: "شوهدت مؤخرا", label: t("شوهدت مؤخرا") },
|
{ value: "recently_viewed", label: t("select.array.order.recently_viewed") },
|
||||||
{ value: "وصلت مؤخرا", label: t("وصلت مؤخرا") },
|
{ value: "recently_arrived", label: t("select.array.order.recently_arrived") },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,19 @@
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Divider, Select } from "antd";
|
import { Divider, Select } from "antd";
|
||||||
import SearchFieldWithSelect from "../../Components/DataTable/SearchFieldWithSelect";
|
import usePagination from "../../Layout/Dashboard/usePagination";
|
||||||
import { translateOptions } from "../../utils/translatedOptions";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { search_array } from "../../Routes";
|
|
||||||
import { useFilterStateState } from "../../zustand/Filter";
|
|
||||||
import { useSearchParams } from "react-router-dom";
|
|
||||||
|
|
||||||
const PaginationColumn = () => {
|
const PaginationColumn = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { Filter, setFilter } = useFilterStateState();
|
const navigate = useNavigate();
|
||||||
const [searchParams, setSearchParams] = useSearchParams();
|
|
||||||
|
|
||||||
const type_param = searchParams.get("type");
|
|
||||||
const [type, setType] = useState(type_param);
|
|
||||||
const translateArray = translateOptions(search_array, t);
|
|
||||||
const handleChange = (value: string) => {
|
const handleChange = (value: string) => {
|
||||||
const newArray = Filter?.filter((item: any) => item.select !== true);
|
navigate(`?per_page=${value}`);
|
||||||
setFilter([
|
|
||||||
...newArray,
|
|
||||||
{ name: value, index: Filter.length, select: true },
|
|
||||||
]);
|
|
||||||
if (type_param) {
|
|
||||||
searchParams.delete("type");
|
|
||||||
setSearchParams(searchParams);
|
|
||||||
}
|
|
||||||
setType(value);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// send this with api request
|
|
||||||
// type: type,
|
|
||||||
// page: currentPage,
|
|
||||||
return (
|
return (
|
||||||
<div className="pagination_column">
|
<div className="pagination_column">
|
||||||
<Select
|
<Select
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { ReactNode, useState } from "react";
|
import React, { ReactNode, useEffect, useState } from "react";
|
||||||
import { FaFilter } from "react-icons/fa";
|
import { FaFilter } from "react-icons/fa";
|
||||||
import { Form, Formik, FormikConfig, FormikHelpers } from "formik";
|
import { Form, Formik, FormikConfig, FormikHelpers } from "formik";
|
||||||
import { Button, ButtonProps, Divider, Modal } from "antd";
|
import { Button, ButtonProps, Divider, Modal } from "antd";
|
||||||
|
|
@ -10,6 +10,9 @@ import { QueryStatusEnum } from "../../../enums/QueryStatus";
|
||||||
import { useObjectToEdit } from "../../../zustand/ObjectToEditState";
|
import { useObjectToEdit } from "../../../zustand/ObjectToEditState";
|
||||||
import FormikForm from "../../../Layout/Dashboard/FormikForm";
|
import FormikForm from "../../../Layout/Dashboard/FormikForm";
|
||||||
import SpinContainer from "../../Layout/SpinContainer";
|
import SpinContainer from "../../Layout/SpinContainer";
|
||||||
|
import { TbFlagCancel } from "react-icons/tb";
|
||||||
|
import { XFilled } from "@ant-design/icons";
|
||||||
|
import { FaXmark } from "react-icons/fa6";
|
||||||
|
|
||||||
type OmitFormikProps = "children" | "initialValues" | "onSubmit";
|
type OmitFormikProps = "children" | "initialValues" | "onSubmit";
|
||||||
|
|
||||||
|
|
@ -36,7 +39,6 @@ const useFilter = () => {
|
||||||
const { filterState, setFilterState, clearFilterState } = useFilterState();
|
const { filterState, setFilterState, clearFilterState } = useFilterState();
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
const [formValues, setFormValues] = useState({});
|
const [formValues, setFormValues] = useState({});
|
||||||
const { setObjectToEdit } = useObjectToEdit();
|
|
||||||
|
|
||||||
// Define the type for the callback
|
// Define the type for the callback
|
||||||
type SubmitCallback = () => void;
|
type SubmitCallback = () => void;
|
||||||
|
|
@ -59,6 +61,10 @@ const useFilter = () => {
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
setFormValues({})
|
||||||
|
setFilterState({})
|
||||||
|
}, [])
|
||||||
|
|
||||||
const FilterBody = ({
|
const FilterBody = ({
|
||||||
onSubmit,
|
onSubmit,
|
||||||
|
|
@ -67,7 +73,7 @@ const useFilter = () => {
|
||||||
getValidationSchema,
|
getValidationSchema,
|
||||||
status,
|
status,
|
||||||
ModelClassName,
|
ModelClassName,
|
||||||
width = "28vw",
|
width = "500px",
|
||||||
isLoading = false,
|
isLoading = false,
|
||||||
setIsOpen,
|
setIsOpen,
|
||||||
isOpen,
|
isOpen,
|
||||||
|
|
@ -82,10 +88,17 @@ const useFilter = () => {
|
||||||
Submit();
|
Submit();
|
||||||
setIsOpen("");
|
setIsOpen("");
|
||||||
};
|
};
|
||||||
const handleCancel = () => {
|
const handleCancel = (isCancel = false) => {
|
||||||
|
|
||||||
|
if(isCancel){
|
||||||
|
setIsOpen("");
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
setIsOpen("");
|
setIsOpen("");
|
||||||
clearFilterState();
|
clearFilterState();
|
||||||
setFormValues({});
|
setFormValues({});
|
||||||
|
|
||||||
};
|
};
|
||||||
const handleOpen = () => {
|
const handleOpen = () => {
|
||||||
setIsOpen(true);
|
setIsOpen(true);
|
||||||
|
|
@ -102,7 +115,7 @@ const useFilter = () => {
|
||||||
footer={null}
|
footer={null}
|
||||||
open={isOpen}
|
open={isOpen}
|
||||||
onOk={handleOpen}
|
onOk={handleOpen}
|
||||||
onCancel={handleCancel}
|
onCancel={()=>{}}
|
||||||
mask={false}
|
mask={false}
|
||||||
style={{ position: "absolute", top: "31.4%", left: "16.7%" }}
|
style={{ position: "absolute", top: "31.4%", left: "16.7%" }}
|
||||||
>
|
>
|
||||||
|
|
@ -115,7 +128,7 @@ const useFilter = () => {
|
||||||
>
|
>
|
||||||
<Form>
|
<Form>
|
||||||
<div>
|
<div>
|
||||||
<header>{t("models.filter")}</header>
|
<header> {t("models.filter")} <FaXmark onClick={()=>handleCancel(true)} /> </header>
|
||||||
<Divider />
|
<Divider />
|
||||||
<main className="main_modal">
|
<main className="main_modal">
|
||||||
{isLoading ? <SpinContainer /> : children}
|
{isLoading ? <SpinContainer /> : children}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ import { useTranslation } from "react-i18next";
|
||||||
import { GoArrowSwitch } from "react-icons/go";
|
import { GoArrowSwitch } from "react-icons/go";
|
||||||
import { useObjectToEdit } from "../../zustand/ObjectToEditState";
|
import { useObjectToEdit } from "../../zustand/ObjectToEditState";
|
||||||
import { QUESTION_OBJECT_KEY } from "../../config/AppKey";
|
import { QUESTION_OBJECT_KEY } from "../../config/AppKey";
|
||||||
|
import { Popover } from "antd";
|
||||||
|
import { CombinationKeyEnum } from "../../enums/CombinationKeyEnum";
|
||||||
|
|
||||||
const Header = () => {
|
const Header = () => {
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
|
|
@ -24,10 +26,23 @@ const Header = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const content = (
|
||||||
|
<div>
|
||||||
|
<p> (CTRL + SHIFT + {CombinationKeyEnum.CHOICE}) {t("header.add_choice")} </p>
|
||||||
|
<p> (CTRL + SHIFT + {CombinationKeyEnum.QUESTION}) {t("header.add_question")} </p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="exercise_add_header mb-4">
|
<header className="exercise_add_header mb-4">
|
||||||
<article>
|
<article>
|
||||||
|
|
||||||
|
|
||||||
|
<Popover content={content} title={t("practical.Abbreviations")}>
|
||||||
<img src="/Icon/QuestionIcon.svg" alt="" />
|
<img src="/Icon/QuestionIcon.svg" alt="" />
|
||||||
|
</Popover>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
{t("practical.add")} {t("models.exercise")}{" "}
|
{t("practical.add")} {t("models.exercise")}{" "}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,10 @@ import BaseForm from "./Model/Malty/Form";
|
||||||
import ModelForm from "./Model/ModelForm";
|
import ModelForm from "./Model/ModelForm";
|
||||||
const AcceptModal = lazy(() => import("./Model/AcceptModal"));
|
const AcceptModal = lazy(() => import("./Model/AcceptModal"));
|
||||||
|
|
||||||
import { useModalState } from "../../../zustand/Modal";
|
|
||||||
const AddPage: React.FC = () => {
|
const AddPage: React.FC = () => {
|
||||||
const { isSuccess: isSuccessAsync, mutateAsync } = useAddQuestionAsync();
|
|
||||||
const { mutate, isSuccess, isLoading } = useAddQuestion();
|
const { mutateAsync } = useAddQuestionAsync();
|
||||||
|
const { mutate, isLoading } = useAddQuestion();
|
||||||
const {
|
const {
|
||||||
isBseQuestion,
|
isBseQuestion,
|
||||||
setTagsSearch,
|
setTagsSearch,
|
||||||
|
|
@ -107,41 +107,10 @@ const AddPage: React.FC = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
// console.log(SavedQuestionData);
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// if (
|
|
||||||
// isSuccessAsync &&
|
|
||||||
// (SavedQuestionData?.Questions?.length > 0 ? isSuccess : true)
|
|
||||||
// ) {
|
|
||||||
// setObjectToEdit(null);
|
|
||||||
// setSuccess(true);
|
|
||||||
// localStorage.removeItem(QUESTION_OBJECT_KEY);
|
|
||||||
// }
|
|
||||||
// if (isSuccess && !SavedQuestionData?.Questions?.length) {
|
|
||||||
// toast.success(t("validation.the_possess_done_successful"));
|
|
||||||
// setObjectToEdit(null);
|
|
||||||
// setSuccess(true);
|
|
||||||
// localStorage.removeItem(QUESTION_OBJECT_KEY);
|
|
||||||
// }
|
|
||||||
// }, [isSuccess, isSuccessAsync]);
|
|
||||||
|
|
||||||
// let cleanedAnswers = cleanObject(SavedQuestionData);
|
|
||||||
// let noChange = hasItems(cleanedAnswers);
|
|
||||||
// console.log(SavedQuestionData);
|
|
||||||
|
|
||||||
// useSaveOnDisconnect(noChange, QUESTION_OBJECT_KEY, SavedQuestionData);
|
|
||||||
|
|
||||||
// const SavedData = getLocalStorageQuestions(QUESTION_OBJECT_KEY);
|
|
||||||
// console.log(SavedData);
|
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
navigate(-1);
|
navigate(-1);
|
||||||
// if (!noChange) {
|
|
||||||
// localStorage.removeItem(QUESTION_OBJECT_KEY);
|
|
||||||
// } else {
|
|
||||||
// setIsOpen(ModalEnum?.QUESTION_ACCEPT);
|
|
||||||
// }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,138 +0,0 @@
|
||||||
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 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 QuestionFIeld from "./QuestionFIeld/QuestionFIeld";
|
|
||||||
import { useObjectToEdit } from "../../../../../zustand/ObjectToEditState";
|
|
||||||
import Choices from "./ChoiceField/Choices";
|
|
||||||
|
|
||||||
const Form = () => {
|
|
||||||
const formik = useFormikContext<any>();
|
|
||||||
const { setSuccess, Success, setSavedQuestionData } = useObjectToEdit();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (Success) {
|
|
||||||
formik.setErrors({});
|
|
||||||
formik.resetForm({ values: {} });
|
|
||||||
setSuccess(false);
|
|
||||||
}
|
|
||||||
}, [Success]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setSavedQuestionData(formik.values);
|
|
||||||
}, [formik?.values]);
|
|
||||||
|
|
||||||
// console.log(formik?.errors);
|
|
||||||
|
|
||||||
const handleAddChoice = (parent_index: number) => {
|
|
||||||
console.log(parent_index);
|
|
||||||
|
|
||||||
formik.setFieldValue(`Questions.[${parent_index}].answers`, [
|
|
||||||
...((formik?.values as any)?.Questions?.[parent_index]
|
|
||||||
.answers 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,
|
|
||||||
answers: [{ 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();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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>
|
|
||||||
|
|
||||||
<Choices parent_index={parent_index} />
|
|
||||||
|
|
||||||
{formik?.values?.Questions?.[parent_index]?.answers?.length <
|
|
||||||
5 && (
|
|
||||||
<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;
|
|
||||||
|
|
@ -1,142 +0,0 @@
|
||||||
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);
|
|
||||||
console.log(formik?.values?.Questions);
|
|
||||||
formik.setFieldValue(`Questions.[${parent_index}].answers`, [
|
|
||||||
...((formik?.values as any)?.Questions?.[parent_index]
|
|
||||||
.answers 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,
|
|
||||||
answers: [{ 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]?.answers ||
|
|
||||||
[]
|
|
||||||
).map((item: Choice, index: number) => {
|
|
||||||
return (
|
|
||||||
<ChoiceFields
|
|
||||||
key={index}
|
|
||||||
parent_index={parent_index}
|
|
||||||
index={index}
|
|
||||||
data={item}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
{formik?.values?.Questions?.[parent_index]?.answers?.length <
|
|
||||||
5 && (
|
|
||||||
<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;
|
|
||||||
|
|
@ -2,12 +2,9 @@ import { Col, Row } from "reactstrap";
|
||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import ValidationField from "../../../../../Components/ValidationField/ValidationField";
|
import ValidationField from "../../../../../Components/ValidationField/ValidationField";
|
||||||
import { useFormikContext } from "formik";
|
import { useFormikContext } from "formik";
|
||||||
import { useModalState } from "../../../../../zustand/Modal";
|
|
||||||
import ChoiceFields from "./ChoiceField/ChoiceFields";
|
|
||||||
import { FaCirclePlus } from "react-icons/fa6";
|
import { FaCirclePlus } from "react-icons/fa6";
|
||||||
import { Choice } from "../../../../../types/Item";
|
import { Choice } from "../../../../../types/Item";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import DynamicTags from "./Tags/DynamicTags";
|
|
||||||
import QuestionFIeld from "./QuestionFIeld/QuestionFIeld";
|
import QuestionFIeld from "./QuestionFIeld/QuestionFIeld";
|
||||||
import { useObjectToEdit } from "../../../../../zustand/ObjectToEditState";
|
import { useObjectToEdit } from "../../../../../zustand/ObjectToEditState";
|
||||||
import Choices from "./ChoiceField/Choices";
|
import Choices from "./ChoiceField/Choices";
|
||||||
|
|
@ -15,6 +12,7 @@ import ImageBoxField from "../../../../../Components/CustomFields/ImageBoxField/
|
||||||
import MaltySelectTag from "./Tags/MaltySelectTag";
|
import MaltySelectTag from "./Tags/MaltySelectTag";
|
||||||
import useKeyCombination from "../../../../../Hooks/useKeyCombination";
|
import useKeyCombination from "../../../../../Hooks/useKeyCombination";
|
||||||
import { CombinationKeyEnum } from "../../../../../enums/CombinationKeyEnum";
|
import { CombinationKeyEnum } from "../../../../../enums/CombinationKeyEnum";
|
||||||
|
import { toast } from "react-toastify";
|
||||||
|
|
||||||
const Form = () => {
|
const Form = () => {
|
||||||
const formik = useFormikContext<any>();
|
const formik = useFormikContext<any>();
|
||||||
|
|
@ -34,7 +32,7 @@ const Form = () => {
|
||||||
|
|
||||||
// console.log(formik?.errors);
|
// console.log(formik?.errors);
|
||||||
|
|
||||||
const handleAddChoice = (parent_index: number) => {
|
const handleAddChoice = (parent_index: number,fromKeyCombination:boolean = false) => {
|
||||||
console.log(parent_index);
|
console.log(parent_index);
|
||||||
|
|
||||||
formik.setFieldValue(`Questions.[${parent_index}].answers`, [
|
formik.setFieldValue(`Questions.[${parent_index}].answers`, [
|
||||||
|
|
@ -46,9 +44,13 @@ const Form = () => {
|
||||||
isCorrect: 0,
|
isCorrect: 0,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
if(fromKeyCombination){
|
||||||
|
toast.success(t("header.new_choice_have_been_added"))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAddQuestion = () => {
|
const handleAddQuestion = (fromKeyCombination:boolean = false) => {
|
||||||
formik.setFieldValue("Questions", [
|
formik.setFieldValue("Questions", [
|
||||||
...((formik?.values as any)?.Questions as Choice[]),
|
...((formik?.values as any)?.Questions as Choice[]),
|
||||||
|
|
||||||
|
|
@ -67,18 +69,21 @@ const Form = () => {
|
||||||
const max_mark = formik?.values?.max_mark + 1;
|
const max_mark = formik?.values?.max_mark + 1;
|
||||||
|
|
||||||
formik.setFieldValue("max_mark", max_mark);
|
formik.setFieldValue("max_mark", max_mark);
|
||||||
|
if(fromKeyCombination){
|
||||||
|
toast.success(t("header.new_question_have_been_added"))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
|
|
||||||
|
|
||||||
const lastQuestions = formik?.values?.Questions?.length -1 ;
|
const lastQuestions = formik?.values?.Questions?.length -1 ;
|
||||||
useKeyCombination({ ctrlKey: true, shiftKey: true, code: CombinationKeyEnum.CHOICE }, () => {
|
useKeyCombination({ ctrlKey: true, shiftKey: true, code: CombinationKeyEnum.CHOICE }, () => {
|
||||||
handleAddChoice(lastQuestions)
|
handleAddChoice(lastQuestions,true)
|
||||||
});
|
});
|
||||||
|
|
||||||
useKeyCombination({ ctrlKey: true, shiftKey: true, code: CombinationKeyEnum.QUESTION }, () => {
|
useKeyCombination({ ctrlKey: true, shiftKey: true, code: CombinationKeyEnum.QUESTION }, () => {
|
||||||
|
|
||||||
handleAddQuestion()
|
handleAddQuestion(true)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -141,7 +146,7 @@ const Form = () => {
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<p className="add_new_button">
|
<p className="add_new_button">
|
||||||
<FaCirclePlus onClick={handleAddQuestion} size={23} />{" "}
|
<FaCirclePlus onClick={()=>handleAddQuestion()} size={23} />{" "}
|
||||||
{t("header.add_new_question")}
|
{t("header.add_new_question")}
|
||||||
</p>
|
</p>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import ImageBoxField from "../../../../Components/CustomFields/ImageBoxField/Ima
|
||||||
import SelectTag from "../../../../Components/CustomFields/SelectTag";
|
import SelectTag from "../../../../Components/CustomFields/SelectTag";
|
||||||
import useKeyCombination from "../../../../Hooks/useKeyCombination";
|
import useKeyCombination from "../../../../Hooks/useKeyCombination";
|
||||||
import { CombinationKeyEnum } from "../../../../enums/CombinationKeyEnum";
|
import { CombinationKeyEnum } from "../../../../enums/CombinationKeyEnum";
|
||||||
|
import { toast } from "react-toastify";
|
||||||
|
|
||||||
const Form = () => {
|
const Form = () => {
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
|
|
@ -31,7 +32,8 @@ const Form = () => {
|
||||||
setSavedQuestionData(formik.values);
|
setSavedQuestionData(formik.values);
|
||||||
}, [formik?.values]);
|
}, [formik?.values]);
|
||||||
|
|
||||||
const handleAddChoice = () => {
|
const handleAddChoice = (fromKeyCombination:boolean = false ) => {
|
||||||
|
|
||||||
formik.setFieldValue("answers", [
|
formik.setFieldValue("answers", [
|
||||||
...((formik?.values as any)?.answers as Choice[]),
|
...((formik?.values as any)?.answers as Choice[]),
|
||||||
{
|
{
|
||||||
|
|
@ -40,12 +42,17 @@ const Form = () => {
|
||||||
isCorrect: 0,
|
isCorrect: 0,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
if(fromKeyCombination){
|
||||||
|
toast.success(t("header.new_choice_have_been_added"))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
useKeyCombination({ ctrlKey: true, shiftKey: true, code: CombinationKeyEnum.CHOICE }, () => {
|
useKeyCombination({ ctrlKey: true, shiftKey: true, code: CombinationKeyEnum.CHOICE }, () => {
|
||||||
|
|
||||||
handleAddChoice()
|
handleAddChoice(true)
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -65,7 +72,7 @@ const Form = () => {
|
||||||
<Choices />
|
<Choices />
|
||||||
{formik?.values?.answers?.length < 5 && (
|
{formik?.values?.answers?.length < 5 && (
|
||||||
<p className="add_new_button">
|
<p className="add_new_button">
|
||||||
<FaCirclePlus onClick={handleAddChoice} size={23} />{" "}
|
<FaCirclePlus onClick={()=>handleAddChoice()} size={23} />{" "}
|
||||||
{t("header.add_new_choice")}
|
{t("header.add_new_choice")}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -132,6 +132,10 @@
|
||||||
border-radius: 10px 10px 0 0;
|
border-radius: 10px 10px 0 0;
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
box-shadow: 0px 0px 4px 2px rgba(0, 0, 0, 0.1);
|
box-shadow: 0px 0px 4px 2px rgba(0, 0, 0, 0.1);
|
||||||
|
|
||||||
|
img{
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.inputSmall {
|
.inputSmall {
|
||||||
width: 100px;
|
width: 100px;
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import { useLocation } from "react-router-dom";
|
||||||
import { PaginationParams } from "../utils/PaginationParams";
|
import { PaginationParams } from "../utils/PaginationParams";
|
||||||
import { filterParams } from "../utils/filterParams";
|
import { filterParams } from "../utils/filterParams";
|
||||||
import useAuthState from "../../zustand/AuthState";
|
import useAuthState from "../../zustand/AuthState";
|
||||||
|
import { useFilterStateState } from "../../zustand/Filter";
|
||||||
|
|
||||||
function useGetQuery(
|
function useGetQuery(
|
||||||
KEY: string | string[],
|
KEY: string | string[],
|
||||||
|
|
@ -12,7 +13,9 @@ function useGetQuery(
|
||||||
options: any = {},
|
options: any = {},
|
||||||
) {
|
) {
|
||||||
const axios = useAxios();
|
const axios = useAxios();
|
||||||
|
const {Filter} = useFilterStateState()
|
||||||
|
const sort_by = Filter?.sort_by ?? null;
|
||||||
|
const name = Filter?.name ?? null;
|
||||||
const { show, pagination, ...remainingParams } = params;
|
const { show, pagination, ...remainingParams } = params;
|
||||||
|
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
@ -20,8 +23,8 @@ function useGetQuery(
|
||||||
const { page, per_page } = PaginationParams(location);
|
const { page, per_page } = PaginationParams(location);
|
||||||
|
|
||||||
const paramToSend = pagination
|
const paramToSend = pagination
|
||||||
? { page: page, per_page: per_page, ...remainingParams }
|
? { page: page, per_page: per_page, ...remainingParams , sort_by,name }
|
||||||
: { ...remainingParams };
|
: { ...remainingParams ,sort_by,name};
|
||||||
|
|
||||||
const filteredParams = filterParams(paramToSend);
|
const filteredParams = filterParams(paramToSend);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,12 @@
|
||||||
"add": "إضافة",
|
"add": "إضافة",
|
||||||
"notification": "الاشعارات",
|
"notification": "الاشعارات",
|
||||||
"change_language": "تغيير اللغة",
|
"change_language": "تغيير اللغة",
|
||||||
"delete_question": "حذف السؤال"
|
"delete_question": "حذف السؤال",
|
||||||
|
"add_choice": "اضافة خيار",
|
||||||
|
"add_question": "اضافة سؤال",
|
||||||
|
"new_choice_have_been_added": "تم إضافة خيار جديد",
|
||||||
|
"new_question_have_been_added": "تم إضافة سؤال جديد",
|
||||||
|
"sort_by":"ترتيب حسب"
|
||||||
},
|
},
|
||||||
"columns": {
|
"columns": {
|
||||||
"id": "الرقم التعريفي",
|
"id": "الرقم التعريفي",
|
||||||
|
|
@ -210,7 +215,8 @@
|
||||||
"delete_this_item": "احذف العنصر",
|
"delete_this_item": "احذف العنصر",
|
||||||
"reset": "اعادة تعيين",
|
"reset": "اعادة تعيين",
|
||||||
"next": "التالي",
|
"next": "التالي",
|
||||||
"prev": "السابق"
|
"prev": "السابق",
|
||||||
|
"Abbreviations": "الاختصارات"
|
||||||
},
|
},
|
||||||
"Table": {
|
"Table": {
|
||||||
"header": "",
|
"header": "",
|
||||||
|
|
@ -642,7 +648,6 @@
|
||||||
"enums": {
|
"enums": {
|
||||||
"first_term": "الفصل الأول",
|
"first_term": "الفصل الأول",
|
||||||
"second_term": "الفصل الثاني"
|
"second_term": "الفصل الثاني"
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"array": {
|
"array": {
|
||||||
"Period": {
|
"Period": {
|
||||||
|
|
@ -672,8 +677,16 @@
|
||||||
"warning": "تحذير",
|
"warning": "تحذير",
|
||||||
"appreciation": "تقدير",
|
"appreciation": "تقدير",
|
||||||
"alert": "تنبيه"
|
"alert": "تنبيه"
|
||||||
|
},
|
||||||
|
"order": {
|
||||||
|
"ascending": "تصاعديا",
|
||||||
|
"descending": "تنازليا",
|
||||||
|
"recently_viewed": "شوهدت مؤخرا",
|
||||||
|
"recently_arrived": "وصلت مؤخرا"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
"dashboard": "لوحة القيادة",
|
"dashboard": "لوحة القيادة",
|
||||||
"course": "الصفوف",
|
"course": "الصفوف",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user