Merge branch 'dev' of into dev

This commit is contained in:
Moaz Dawalibi 2024-09-12 11:58:41 +03:00
commit d56c4a06bf
22 changed files with 177 additions and 665 deletions

View File

@ -43,13 +43,11 @@ const SelectTag: React.FC = () => {
: [];
console.log(options);
console.log(formik?.values?.tags);
const value = formik?.values?.tags?.map((item: any) => item?.id ?? item) ?? [];
const AllOptions = [...options, ...additionalData]
console.log(AllOptions);
return (
<div className="SelectTag">

View File

@ -2,6 +2,8 @@ import React, { useState, useEffect, useRef } from "react";
import { useTranslation } from "react-i18next";
import { IoSearch } from "react-icons/io5";
import { useLocation, useNavigate } from "react-router-dom";
import { useFilterStateState } from "../../zustand/Filter";
import { useDebounce } from "../../utils/useDebounce";
interface Props {
placeholder: string;
@ -11,36 +13,25 @@ interface Props {
const SearchField: React.FC<Props> = ({ placeholder, searchBy }) => {
const [isOpen, setIsOpen] = useState(false);
const [searchQuery, setSearchQuery] = useState<string>("");
const location = useLocation();
const navigate = useNavigate();
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);
setSearchQuery(searchParams.get(searchBy) || "");
}, [location.search, searchBy]);
const {setFilter} = useFilterStateState()
const handleInputChange = (value: string) => {
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 = () => {
setIsOpen(!isOpen);
};
@ -69,7 +60,7 @@ const SearchField: React.FC<Props> = ({ placeholder, searchBy }) => {
className="search__input"
placeholder={t(placeholder)}
value={searchQuery}
onChange={(e) => handleInputChange(e.target.value)}
onChange={(e) => {handleInputChange(e.target.value) ; handleInputChangeWithDebounce(e.target.value)}}
/>
</div>
</div>

View File

@ -1,54 +1,36 @@
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
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 { useFilterStateState } from "../../zustand/Filter";
const OrderBySelect = () => {
const { t } = useTranslation();
const { Filter, 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 {setFilter} = useFilterStateState()
const handleChange = (value: string) => {
const newArray = Filter?.filter((item: any) => item.select !== true);
setFilter([
...newArray,
{ name: value, index: Filter.length, select: true },
]);
if (type_param) {
searchParams.delete("type");
setSearchParams(searchParams);
}
setType(value);
setFilter({
sort_by:value
})
};
// send this with api request
// type: type,
// page: currentPage,
return (
<div className="order_by_filter">
<Select
className="order_by_select"
style={{ width: 200 }}
size="large"
allowClear
placeholder={
<div>
<TbReorder className="addition_select_icon" /> {t("ترتيب حسب")}{" "}
<TbReorder className="addition_select_icon" /> {t("header.sort_by")}{" "}
</div>
}
onChange={handleChange}
options={[
{ value: "تصاعديا", label: t("تصاعديا") },
{ value: "تنازليا", label: t("تنازليا") },
{ value: "شوهدت مؤخرا", label: t("شوهدت مؤخرا") },
{ value: "وصلت مؤخرا", label: t("وصلت مؤخرا") },
{ value: "ascending", label: t("select.array.order.ascending") },
{ value: "descending", label: t("select.array.order.descending") },
{ value: "recently_viewed", label: t("select.array.order.recently_viewed") },
{ value: "recently_arrived", label: t("select.array.order.recently_arrived") },
]}
/>
</div>

View File

@ -1,36 +1,19 @@
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
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 usePagination from "../../Layout/Dashboard/usePagination";
import { useNavigate } from "react-router-dom";
const PaginationColumn = () => {
const { t } = useTranslation();
const { Filter, setFilter } = useFilterStateState();
const [searchParams, setSearchParams] = useSearchParams();
const navigate = useNavigate();
const type_param = searchParams.get("type");
const [type, setType] = useState(type_param);
const translateArray = translateOptions(search_array, t);
const handleChange = (value: string) => {
const newArray = Filter?.filter((item: any) => item.select !== true);
setFilter([
...newArray,
{ name: value, index: Filter.length, select: true },
]);
if (type_param) {
searchParams.delete("type");
setSearchParams(searchParams);
}
setType(value);
navigate(`?per_page=${value}`);
};
// send this with api request
// type: type,
// page: currentPage,
return (
<div className="pagination_column">
<Select

View File

@ -1,4 +1,4 @@
import React, { ReactNode, useState } from "react";
import React, { ReactNode, useEffect, useState } from "react";
import { FaFilter } from "react-icons/fa";
import { Form, Formik, FormikConfig, FormikHelpers } from "formik";
import { Button, ButtonProps, Divider, Modal } from "antd";
@ -9,6 +9,9 @@ import { ModalEnum } from "../../../enums/Model";
import { QueryStatusEnum } from "../../../enums/QueryStatus";
import { useObjectToEdit } from "../../../zustand/ObjectToEditState";
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";
@ -35,9 +38,6 @@ const useFilter = () => {
const { filterState, setFilterState, clearFilterState } = useFilterState();
const [t] = useTranslation();
const [formValues, setFormValues] = useState({});
const { setObjectToEdit } = useObjectToEdit();
console.log(formValues);
// Define the type for the callback
type SubmitCallback = () => void;
@ -59,6 +59,10 @@ const useFilter = () => {
</span>
);
};
useEffect(() => {
setFormValues({})
setFilterState({})
}, [])
const FilterBody = ({
onSubmit,
@ -67,7 +71,7 @@ const useFilter = () => {
getValidationSchema,
status,
ModelClassName,
width = "28vw",
width = "500px",
isLoading = false,
setIsOpen,
isOpen,
@ -85,10 +89,17 @@ const useFilter = () => {
Submit();
setIsOpen("");
};
const handleCancel = () => {
const handleCancel = (isCancel = false) => {
if(isCancel){
setIsOpen("");
return ;
}
setIsOpen("");
clearFilterState();
setFormValues({});
};
const handleOpen = () => {
setIsOpen(true);
@ -105,7 +116,7 @@ const useFilter = () => {
footer={null}
open={isOpen}
onOk={handleOpen}
onCancel={handleCancel}
onCancel={()=>{}}
mask={false}
style={{ position: "absolute", top: "31.4%", left: "16.7%" }}
>
@ -118,7 +129,7 @@ const useFilter = () => {
>
<Form>
<div>
<header>{t("models.filter")}</header>
<header> {t("models.filter")} <FaXmark onClick={()=>handleCancel(true)} /> </header>
<Divider />
<main className="main_modal">
{isLoading ? <SpinContainer /> : children}

View File

@ -4,6 +4,8 @@ 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 { CombinationKeyEnum } from "../../enums/CombinationKeyEnum";
const Header = () => {
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 (
<header className="exercise_add_header mb-4">
<article>
<Popover content={content} title={t("practical.Abbreviations")}>
<img src="/Icon/QuestionIcon.svg" alt="" />
</Popover>
<div>
{t("practical.add")} {t("models.exercise")}{" "}
</div>

View File

@ -8,7 +8,6 @@ import useSetPageTitle from "../../../Hooks/useSetPageTitle";
import { ModalEnum } from "../../../enums/Model";
import { useDeleteUnit } from "../../../api/unit";
import { useGetAllGrade } from "../../../api/grade";
import { useGetAllCurriculum } from "../../../api/curriculum";
import PageHeader from "../../../Layout/Dashboard/PageHeader";
import FilterLayout from "../../../Layout/Dashboard/FilterLayout";
import FilterForm from "./Model/FilterForm";
@ -34,13 +33,10 @@ const TableHeader = () => {
const { data: grade } = useGetAllGrade({
show: grade_id,
});
const { data: Curriculum } = useGetAllCurriculum({
show: curriculum_id,
});
const gradeName = grade?.data?.name ?? "";
const SubjectName = Subject?.data?.name ?? "";
const CurriculumName = Curriculum?.data?.name ?? "";
useSetPageTitle(
t(`page_header.grade`) +
"/" +
@ -50,10 +46,6 @@ const TableHeader = () => {
"/" +
SubjectName +
"/" +
t("PageTitle.curriculum") +
"/" +
CurriculumName +
"/" +
t("PageTitle.unit"),
);

View File

@ -36,13 +36,10 @@ const TableHeader = () => {
const { data: grade } = useGetAllGrade({
show: grade_id,
});
const { data: Curriculum } = useGetAllCurriculum({
show: curriculum_id,
});
const gradeName = grade?.data?.name ?? "";
const SubjectName = Subject?.data?.name ?? "";
const CurriculumName = Curriculum?.data?.name ?? "";
const unitName = unit?.data?.name ?? "";
useSetPageTitle(
@ -54,10 +51,6 @@ const TableHeader = () => {
"/" +
SubjectName +
"/" +
t("PageTitle.curriculum") +
"/" +
CurriculumName +
"/" +
t("PageTitle.unit") +
"/" +
unitName +

View File

@ -1,5 +1,5 @@
import React, { Suspense, lazy, useEffect } from "react";
import { Modal, Spin } from "antd";
import React, { Suspense, lazy } from "react";
import { Spin } from "antd";
import FormikForm from "../../../Layout/Dashboard/FormikFormModel";
import {
getInitialValues,
@ -20,21 +20,19 @@ import BaseForm from "./Model/Malty/Form";
import ModelForm from "./Model/ModelForm";
const AcceptModal = lazy(() => import("./Model/AcceptModal"));
import { useModalState } from "../../../zustand/Modal";
const AddPage: React.FC = () => {
const { isSuccess: isSuccessAsync, mutateAsync } = useAddQuestionAsync();
const { mutate, isSuccess, isLoading } = useAddQuestion();
const { mutateAsync } = useAddQuestionAsync();
const { mutate, isLoading } = useAddQuestion();
const {
isBseQuestion,
setTagsSearch,
setObjectToEdit,
objectToEdit,
} = useObjectToEdit();
const { setIsOpen } = useModalState((state) => state);
const [t] = useTranslation();
const { unit_id, curriculum_id, grade_id, subject_id, lesson_id } =
const { subject_id, lesson_id } =
useParams<ParamsEnum>();
@ -109,41 +107,10 @@ const AddPage: React.FC = () => {
};
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 = () => {
navigate(-1);
// if (!noChange) {
// localStorage.removeItem(QUESTION_OBJECT_KEY);
// } else {
// setIsOpen(ModalEnum?.QUESTION_ACCEPT);
// }
};

View File

@ -1,10 +1,9 @@
import React, { useEffect, useState } from "react";
import { Input, Modal, Spin } from "antd";
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 { useObjectToEdit } from "../../../../zustand/ObjectToEditState";
import { QUESTION_OBJECT_KEY } from "../../../../config/AppKey";
const AcceptModal: React.FC = () => {

View File

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

View File

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

View File

@ -2,12 +2,9 @@ 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";
@ -15,6 +12,7 @@ import ImageBoxField from "../../../../../Components/CustomFields/ImageBoxField/
import MaltySelectTag from "./Tags/MaltySelectTag";
import useKeyCombination from "../../../../../Hooks/useKeyCombination";
import { CombinationKeyEnum } from "../../../../../enums/CombinationKeyEnum";
import { toast } from "react-toastify";
const Form = () => {
const formik = useFormikContext<any>();
@ -34,7 +32,7 @@ const Form = () => {
// console.log(formik?.errors);
const handleAddChoice = (parent_index: number) => {
const handleAddChoice = (parent_index: number,fromKeyCombination:boolean = false) => {
console.log(parent_index);
formik.setFieldValue(`Questions.[${parent_index}].answers`, [
@ -46,9 +44,13 @@ const Form = () => {
isCorrect: 0,
},
]);
if(fromKeyCombination){
toast.success(t("header.new_choice_have_been_added"))
}
};
const handleAddQuestion = () => {
const handleAddQuestion = (fromKeyCombination:boolean = false) => {
formik.setFieldValue("Questions", [
...((formik?.values as any)?.Questions as Choice[]),
@ -67,18 +69,21 @@ const Form = () => {
const max_mark = formik?.values?.max_mark + 1;
formik.setFieldValue("max_mark", max_mark);
if(fromKeyCombination){
toast.success(t("header.new_question_have_been_added"))
}
};
const [t] = useTranslation();
const lastQuestions = formik?.values?.Questions?.length -1 ;
useKeyCombination({ ctrlKey: true, shiftKey: true, code: CombinationKeyEnum.CHOICE }, () => {
handleAddChoice(lastQuestions)
handleAddChoice(lastQuestions,true)
});
useKeyCombination({ ctrlKey: true, shiftKey: true, code: CombinationKeyEnum.QUESTION }, () => {
handleAddQuestion()
handleAddQuestion(true)
});
@ -141,7 +146,7 @@ const Form = () => {
)}
<p className="add_new_button">
<FaCirclePlus onClick={handleAddQuestion} size={23} />{" "}
<FaCirclePlus onClick={()=>handleAddQuestion()} size={23} />{" "}
{t("header.add_new_question")}
</p>
</Row>

View File

@ -1,11 +1,9 @@
import { Row } from "reactstrap";
import ValidationField from "../../../../Components/ValidationField/ValidationField";
import { useFormikContext } from "formik";
import ChoiceFields from "./Field/ChoiceFields";
import { FaCirclePlus } from "react-icons/fa6";
import { Choice } from "../../../../types/Item";
import { useTranslation } from "react-i18next";
import DynamicTags from "./Tags/DynamicTags";
import { useObjectToEdit } from "../../../../zustand/ObjectToEditState";
import { useEffect } from "react";
import Choices from "./Field/Choices";
@ -13,6 +11,7 @@ import ImageBoxField from "../../../../Components/CustomFields/ImageBoxField/Ima
import SelectTag from "../../../../Components/CustomFields/SelectTag";
import useKeyCombination from "../../../../Hooks/useKeyCombination";
import { CombinationKeyEnum } from "../../../../enums/CombinationKeyEnum";
import { toast } from "react-toastify";
const Form = () => {
const [t] = useTranslation();
@ -33,7 +32,8 @@ const Form = () => {
setSavedQuestionData(formik.values);
}, [formik?.values]);
const handleAddChoice = () => {
const handleAddChoice = (fromKeyCombination:boolean = false ) => {
formik.setFieldValue("answers", [
...((formik?.values as any)?.answers as Choice[]),
{
@ -42,12 +42,17 @@ const Form = () => {
isCorrect: 0,
},
]);
if(fromKeyCombination){
toast.success(t("header.new_choice_have_been_added"))
}
};
useKeyCombination({ ctrlKey: true, shiftKey: true, code: CombinationKeyEnum.CHOICE }, () => {
handleAddChoice()
handleAddChoice(true)
});
@ -67,7 +72,7 @@ const Form = () => {
<Choices />
{formik?.values?.answers?.length < 5 && (
<p className="add_new_button">
<FaCirclePlus onClick={handleAddChoice} size={23} />{" "}
<FaCirclePlus onClick={()=>handleAddChoice()} size={23} />{" "}
{t("header.add_new_choice")}
</p>
)}

View File

@ -1,91 +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 = () => {
const formik = useFormikContext<any>();
const [t] = useTranslation();
const { TagsSearch, setTagsSearch, currentTag } = useObjectToEdit();
const { data } = useGetAllTag({
name: TagsSearch,
});
const suggests = data?.data;
const handleAddChoice = () => {
const length = formik?.values?.tags.length;
const lastElement = formik?.values?.tags[length - 1]?.name;
setTagsSearch;
if (lastElement !== "") {
formik.setFieldValue("tags", [
...((formik?.values as any)?.tags as any[]),
{
id: length + "_new",
name: "",
key: length,
},
]);
} else {
}
};
// console.log(formik?.values);
// console.log(currentTag);
const handleChoice = (item: any) => {
const length = formik.values.tags.length;
console.log(currentTag);
formik.setFieldValue(`tags[${currentTag}]`, { ...item, key: length });
setTagsSearch(null);
};
// console.log(formik?.values?.tags?.length);
return (
<div className="DynamicTags">
{formik?.values?.tags?.length < 1 && (
<p className="add_new_button">
<FaCirclePlus size={23} onClick={handleAddChoice} />{" "}
{t("header.add_tag")}
</p>
)}
<div className="tag_container">
<div className="tags">
{(((formik?.values as any)?.tags as any[]) || []).map(
(item: any, index: number) => {
return <Tag key={index} index={index} data={item} />;
},
)}
</div>
{formik?.values?.tags?.length > 0 && (
<p className="add_new_button">
<FaCirclePlus onClick={handleAddChoice} size={20} />
</p>
)}
</div>
{TagsSearch && (
<div className="suggests">
{suggests?.map((item: any, index: number) => {
return (
<div
className="suggested"
key={index}
onClick={() => handleChoice(item)}
>
{item?.name}
</div>
);
})}
</div>
)}
</div>
);
};
export default DynamicTags;

View File

@ -1,75 +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 }: { data: any; index: number }) => {
const inputRef = useRef<HTMLInputElement>(null);
const formik = useFormikContext<any>();
const { setTagsSearch, setCurrentTag } = useObjectToEdit();
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
const DEBOUNCE_DELAY = 500;
useEffect(() => {
if (inputRef.current) {
inputRef.current.style.width = `${(formik?.values?.tags[index]?.name?.length + 1) * 8}px`;
}
}, [formik?.values?.tags[index]?.name]);
const handleEditInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
// console.log(e.target.value);
formik.setFieldValue(`tags[${index}].name`, e.target.value);
// setTagsSearch(e.target.value)
formik.setFieldValue(`tags.[${index}]`, {
key: index,
name: e.target.value,
id: `${index}_key`,
});
setCurrentTag(index);
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
timeoutRef.current = setTimeout(() => {
setTagsSearch(e.target.value);
}, DEBOUNCE_DELAY);
};
const handleInputBlur = () => {
// setTagsSearch(null)
};
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("tags", currentTags);
// Reset search state if needed
setTagsSearch(null);
};
return (
<div className="tag">
<input
ref={inputRef}
className="tagInput"
type="text"
value={formik?.values?.tags[index]?.name}
onChange={handleEditInputChange}
onBlur={handleInputBlur}
/>
<FaTrash onClick={handleDeleteChoice} />
</div>
);
};
export default Tag;

View File

@ -7,7 +7,6 @@ export const getInitialValues = (objectToEdit: Question): any => {
const tags = objectToEdit?.tags?.map((item: any, index: number) => {
return { ...item };
});
console.log(tags);
return {
id: objectToEdit?.id ?? null,

View File

@ -132,6 +132,10 @@
border-radius: 10px 10px 0 0;
margin: 0 !important;
box-shadow: 0px 0px 4px 2px rgba(0, 0, 0, 0.1);
img{
cursor: pointer;
}
}
.inputSmall {
width: 100px;

View File

@ -4,6 +4,7 @@ import { useLocation } from "react-router-dom";
import { PaginationParams } from "../utils/PaginationParams";
import { filterParams } from "../utils/filterParams";
import useAuthState from "../../zustand/AuthState";
import { useFilterStateState } from "../../zustand/Filter";
function useGetQuery(
KEY: string | string[],
@ -12,7 +13,9 @@ function useGetQuery(
options: any = {},
) {
const axios = useAxios();
const {Filter} = useFilterStateState()
const sort_by = Filter?.sort_by ?? null;
const name = Filter?.name ?? null;
const { show, pagination, ...remainingParams } = params;
const location = useLocation();
@ -20,8 +23,8 @@ function useGetQuery(
const { page, per_page } = PaginationParams(location);
const paramToSend = pagination
? { page: page, per_page: per_page, ...remainingParams }
: { ...remainingParams };
? { page: page, per_page: per_page, ...remainingParams , sort_by,name }
: { ...remainingParams ,sort_by,name};
const filteredParams = filterParams(paramToSend);

View File

@ -110,7 +110,12 @@
"add": "إضافة",
"notification": "الاشعارات",
"change_language": "تغيير اللغة",
"delete_question": "حذف السؤال"
"delete_question": "حذف السؤال",
"add_choice": "اضافة خيار",
"add_question": "اضافة سؤال",
"new_choice_have_been_added": "تم إضافة خيار جديد",
"new_question_have_been_added": "تم إضافة سؤال جديد",
"sort_by":"ترتيب حسب"
},
"columns": {
"id": "الرقم التعريفي",
@ -158,13 +163,13 @@
"isBase": "سؤال رئيسي",
"question_options_count": "عدد الخيارات",
"procedure": "اجراء",
"icon":"الايقونة",
"canAnswersBeShuffled":"يمكن خلط الإجابات",
"phone_number":"رقم الهاتف",
"key":"المفتاح",
"expiration_date":"تاريخ الالغاء",
"activation_date":"تاريخ التنشيط",
"first_name":"الاسم الأول"
"icon": "الايقونة",
"canAnswersBeShuffled": "يمكن خلط الإجابات",
"phone_number": "رقم الهاتف",
"key": "المفتاح",
"expiration_date": "تاريخ الالغاء",
"activation_date": "تاريخ التنشيط",
"first_name": "الاسم الأول"
},
"practical": {
"to_confirm_deletion_please_re_enter": "لتأكيد الحذف، يرجى إعادة الإدخال",
@ -210,7 +215,8 @@
"delete_this_item": "احذف العنصر",
"reset": "اعادة تعيين",
"next": "التالي",
"prev": "السابق"
"prev": "السابق",
"Abbreviations": "الاختصارات"
},
"Table": {
"header": "",
@ -280,8 +286,8 @@
"user": "مستخدم",
"user_details": "تفاصيل المستخدم",
"reseller_details": "تفاصيل اعادة البيع",
"reseller":"البائعين",
"student_package":"حزمة الطالب"
"reseller": "البائعين",
"student_package": "حزمة الطالب"
},
"education_class_actions": {
"Student_Records": "سجلات الطلاب",
@ -385,8 +391,8 @@
"hint": "شرح الاختيار",
"hint_question": "شرح السؤال",
"_": "",
"key":"المفتاح",
"canAnswersBeShuffled":"يمكن خلط الإجابات"
"key": "المفتاح",
"canAnswersBeShuffled": "يمكن خلط الإجابات"
},
"select": {
"Payments": {
@ -642,38 +648,45 @@
"enums": {
"first_term": "الفصل الأول",
"second_term": "الفصل الثاني"
},
"array": {
"Period": {
"Today": "اليوم",
"First": "الأول",
"Second": "الثاني",
"Third": "الثالث",
"Fourth": "الرابع",
"Fifth": "الخامس",
"Sixth": "السادس",
"Seventh": "السابع"
},
"Days": {
"Sunday": "الأحد",
"Monday": "الاثنين",
"Tuesday": "الثلاثاء",
"Wednesday": "الأربعاء",
"Thursday": "الخميس",
"Friday": " الجمعة",
"Saturday": "السبت"
},
"UserInfo": {
"course": "الصف",
"education_class": "الشعبة",
"nationality": "الجنسية",
"birthday": "تاريخ الميلاد",
"warning": "تحذير",
"appreciation": "تقدير",
"alert": "تنبيه"
},
"order": {
"ascending": "تصاعديا",
"descending": "تنازليا",
"recently_viewed": "شوهدت مؤخرا",
"recently_arrived": "وصلت مؤخرا"
}
}
},
"array": {
"Period": {
"Today": "اليوم",
"First": "الأول",
"Second": "الثاني",
"Third": "الثالث",
"Fourth": "الرابع",
"Fifth": "الخامس",
"Sixth": "السادس",
"Seventh": "السابع"
},
"Days": {
"Sunday": "الأحد",
"Monday": "الاثنين",
"Tuesday": "الثلاثاء",
"Wednesday": "الأربعاء",
"Thursday": "الخميس",
"Friday": " الجمعة",
"Saturday": "السبت"
},
"UserInfo": {
"course": "الصف",
"education_class": "الشعبة",
"nationality": "الجنسية",
"birthday": "تاريخ الميلاد",
"warning": "تحذير",
"appreciation": "تقدير",
"alert": "تنبيه"
}
},
"sidebar": {
"dashboard": "لوحة القيادة",
"course": "الصفوف",
@ -702,9 +715,9 @@
"report": "تقرير",
"user": "مستخدم",
"student": "الطلاب",
"reseller":"البائعين",
"param":"معامل",
"student_package":"حزمة الطالب"
"reseller": "البائعين",
"param": "معامل",
"student_package": "حزمة الطالب"
},
"message": {
"some_thing_went_wrong": "حدث خطأ ما",
@ -730,8 +743,8 @@
"curriculum": "مقرر",
"question": "السؤال",
"user": "مستخدم",
"param":"معامل",
"student_package":"حزمة الطالب"
"param": "معامل",
"student_package": "حزمة الطالب"
},
"page_header": {
"dashboard": "لوحة القيادة / الصفحة الرئيسية",
@ -765,13 +778,13 @@
"grade": "الصفوف",
"report": "تقرير",
"user": "مستخدم",
"reseller":" لوحة القيادة / البائعين",
"param":"معامل",
"student_package":"حزمة الطالب"
"reseller": " لوحة القيادة / البائعين",
"param": "معامل",
"student_package": "حزمة الطالب"
},
"table": {
"student": "قائمة الطلاب",
"reseller":"البائعين"
"reseller": "البائعين"
},
"alphabet": {
"A": "A",

View File

@ -7,9 +7,7 @@ export const RoleByType = (item: { type?: string }):boolean=>{
const LocalType = getLocalStorage(USER_KEY)?.type ?? undefined ;
const isAdmin = LocalType === UserTypeEnum.ADMIN ;
const isReSeller = LocalType === UserTypeEnum.RE_SELLER;
const isAdminRoute = type === UserTypeEnum.ADMIN ;
const isReSellerRoute = type === UserTypeEnum.RE_SELLER;
console.log(LocalType);
if(!LocalType){
return false