Merge branch 'dev' of into dev

This commit is contained in:
Moaz Dawalibi 2024-09-17 11:40:14 +03:00
commit 3a877b5053
34 changed files with 437 additions and 133 deletions

View File

@ -27,6 +27,7 @@ const ImageBoxField = ({ name }: any) => {
const handleFileChange = (event: any) => { const handleFileChange = (event: any) => {
const file = event.target.files[0]; const file = event.target.files[0];
if (file) { if (file) {
const maxSize = 2 * 1024 * 1024; const maxSize = 2 * 1024 * 1024;
@ -42,6 +43,8 @@ const ImageBoxField = ({ name }: any) => {
if (file) { if (file) {
generateImagePreview(file, setImagePreview); generateImagePreview(file, setImagePreview);
console.log(file,"file");
formik.setFieldValue(name, file); formik.setFieldValue(name, file);
} }
}; };
@ -55,7 +58,7 @@ const ImageBoxField = ({ name }: any) => {
const handleCancel = () => { const handleCancel = () => {
setImagePreview(""); setImagePreview("");
formik.setFieldValue(name, ""); formik.setFieldValue(name, null);
if (fileInputRef.current) { if (fileInputRef.current) {
fileInputRef.current.value = ""; fileInputRef.current.value = "";
@ -79,9 +82,9 @@ const ImageBoxField = ({ name }: any) => {
</div> </div>
<div className="ImageBox" onClick={handleButtonClick}> <div className="ImageBox" onClick={handleButtonClick}>
{imagePreview ? ( {imagePreview ? (
<img src={imagePreview} onClick={handleButtonClick} alt="Preview" className="imagePreview" /> <img src={imagePreview} alt="Preview" className="imagePreview" />
) : ( ) : (
<ImageIcon onClick={handleButtonClick} className="ImageBoxIcon" /> <ImageIcon className="ImageBoxIcon" />
)} )}
</div> </div>
<input <input

View File

@ -9,20 +9,32 @@ const SelectTag: React.FC = () => {
const [searchValue, setSearchValue] = useState<string>(""); const [searchValue, setSearchValue] = useState<string>("");
const [fieldValue, setFieldValue] = useState<string>(""); const [fieldValue, setFieldValue] = useState<string>("");
const [NewAdditionalData, setNewAdditionalData] = useState({})
const formik = useFormikContext<any>(); const formik = useFormikContext<any>();
const handleChange = (value: string[]) => { const handleChange = (value: any,option:any) => {
console.log(option);
console.log(value); console.log(value);
const newSelectedOption = option?.pop()
console.log(newSelectedOption);
const newObject = {
id:newSelectedOption?.id,
name:newSelectedOption?.name
}
setNewAdditionalData(newObject)
formik.setFieldValue("tags", value); formik.setFieldValue("tags", value);
setSearchValue(""); setSearchValue("");
setFieldValue(""); setFieldValue("");
}; };
const handleSearch = useDebounce((value: string) => { const handleSearch = useDebounce((value: string) => {
console.log(value,"value");
setSearchValue(value); setSearchValue(value);
}); });
const handleFieldChange = (value: string) => { const handleFieldChange = (value: string) => {
setFieldValue(value); setFieldValue(value);
}; };
@ -36,18 +48,33 @@ const SelectTag: React.FC = () => {
}); });
const [t] = useTranslation(); const [t] = useTranslation();
const initialData = formik?.values?.tags?.filter((item:any)=>{
return item?.id
}) ?? []
const options = data?.data ?? []; const options = data?.data ?? [];
const additionalData = const additionalData =
options.length < 1 && searchValue.length > 1 && !isLoading options.length < 1 && searchValue.length > 1 && !isLoading
? [{ id: searchValue, name: searchValue }] ? [{ id: searchValue, name: searchValue }]
: []; : [];
const value = const value =
formik?.values?.tags?.map((item: any) => item?.id ?? item) ?? []; formik?.values?.tags?.map((item: any) => item?.id ?? item) ?? [];
const AllOptions = [...options, ...additionalData]; const AllOptions = [...options, ...additionalData,NewAdditionalData, ...(initialData)];
const uniqueOptions = Array.from(
new Map(
AllOptions
.filter(item => Object.keys(item).length > 0) // Filter out empty objects
.map(item => [item.id, item]) // Create [id, item] pairs to ensure uniqueness
).values()
);
return ( return (
<div className="SelectTag"> <div className="SelectTag">
<label htmlFor="">{t("models.tag")}</label> <label htmlFor="">{t("models.tag")}</label>
@ -58,7 +85,7 @@ const SelectTag: React.FC = () => {
placeholder="" placeholder=""
fieldNames={{ label: "name", value: "id" }} fieldNames={{ label: "name", value: "id" }}
onChange={handleChange} onChange={handleChange}
options={AllOptions} options={uniqueOptions}
filterOption={false} filterOption={false}
loading={isLoading} loading={isLoading}
notFoundContent={isLoading ? <Spin /> : t("practical.not_found")} notFoundContent={isLoading ? <Spin /> : t("practical.not_found")}

View File

@ -7,7 +7,6 @@
margin-bottom: 10px; margin-bottom: 10px;
position: relative; position: relative;
min-height: 80px; min-height: 80px;
// padding-inline: 20px;
> * { > * {
width: 100% !important; width: 100% !important;
min-width: 150px; min-width: 150px;

View File

@ -1,37 +1,59 @@
import { useFormikContext } from "formik"; import { useFormikContext } from "formik";
import React from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; 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 { Checkbox, CheckboxProps, Popconfirm, Popover } from "antd";
import { Popconfirm, Popover } from "antd";
import { CombinationKeyEnum } from "../../enums/CombinationKeyEnum"; import { CombinationKeyEnum } from "../../enums/CombinationKeyEnum";
import { PopconfirmProps } from "antd/lib"; import { PopconfirmProps } from "antd/lib";
import { SettingFilled } from "@ant-design/icons";
const Header = () => { const Header = () => {
const [t] = useTranslation(); const [t] = useTranslation();
const { values, setFieldValue, setValues } = useFormikContext<any>(); const { values, setValues } = useFormikContext<any>();
const { isBseQuestion, setIsBseQuestion } = useObjectToEdit(); const { isBseQuestion, setIsBseQuestion,ShowHint,setShowHint } = useObjectToEdit();
const { setSavedQuestionData } = useObjectToEdit(); // const [Setting, setSetting] = useState(false)
const isEdited = ()=>{
if(isBseQuestion || values?.isBase === 1){
const content = !values?.content ;
const content_image = !values?.content_image ;
const Questions = values?.Questions?.length <= 1 && values?.Questions?.[0]?.answers?.length === 0 ;
const defaultQuestionHint = Object.keys(values?.Questions?.[0] ?? {})?.length <= 1
if(content && content_image && Questions && defaultQuestionHint) {
return false
}
}else{
const content = !values?.content ;
const content_image = !values?.content_image ;
const hint = !values?.hint ;
const answers = !(values?.answers?.length > 0) ;
const tags = !(values?.tags?.length > 0) ;
if(content && content_image && hint && answers && tags) {
return false
}
}
return true
}
const handleChange = () => { const handleChange = () => {
setSavedQuestionData(null);
localStorage.removeItem(QUESTION_OBJECT_KEY);
if (isBseQuestion) { if (isBseQuestion) {
setIsBseQuestion(false); setIsBseQuestion(false);
setValues(null); setValues(null);
setFieldValue("isBase", 0);
} else { } else {
setIsBseQuestion(true); setIsBseQuestion(true);
setValues(null); setValues(null);
setFieldValue("isBase", 1);
} }
}; };
const confirm: PopconfirmProps['onConfirm'] = (e) => { const confirm: PopconfirmProps['onConfirm'] = (e) => {
console.log(e);
setTimeout(() => { setTimeout(() => {
handleChange() handleChange() ;
}, 500); }, 500);
}; };
@ -50,6 +72,25 @@ const Header = () => {
</div> </div>
); );
const handleOpenChange = (newOpen: boolean) => {
// setSetting(newOpen);
};
const onChange: CheckboxProps['onChange'] = (e) => {
setShowHint(e.target.checked);
};
const contentSetting = (
<div>
<Checkbox checked={ShowHint} onChange={onChange}>
{ t("header.show_hint")}
</Checkbox>
</div>
);
return ( return (
<header className="exercise_add_header mb-4"> <header className="exercise_add_header mb-4">
<article> <article>
@ -62,7 +103,17 @@ const Header = () => {
</div> </div>
</article> </article>
<div> <div>
<Popconfirm
<div className="question_header_setting">
<Popover onOpenChange={handleOpenChange} trigger="click" content={contentSetting}>
<SettingFilled/>
</Popover>
</div>
{
isEdited() ?
<Popconfirm
title={t("header.this_will_un_do_all_your_changes")} title={t("header.this_will_un_do_all_your_changes")}
okText={t("practical.yes")} okText={t("practical.yes")}
cancelText={t("practical.no")} cancelText={t("practical.no")}
@ -77,6 +128,23 @@ const Header = () => {
: t("header.exercise")} : t("header.exercise")}
</Popconfirm> </Popconfirm>
:
<>
<GoArrowSwitch onClick={()=>confirm()} className="m-2" />
{isBseQuestion || values?.isBase === 1
? t("header.malty_exercise")
: t("header.exercise")}
</>
}
</div> </div>
</header> </header>
); );

View File

@ -33,7 +33,7 @@ const FormikFormModel: React.FC<FormikFormProps> = ({
> >
{(formik) => { {(formik) => {
useEffect(() => { useEffect(() => {
if (isOpen === "") { if (isOpen === "" || isOpen === "isSuccess") {
formik.setErrors({}); formik.setErrors({});
formik.resetForm(); formik.resetForm();
} }

View File

@ -1,6 +1,7 @@
import React, { lazy, Suspense } from "react"; import React, { lazy, Suspense, useEffect } from "react";
import { useAddKeyToData, Table, useTranslation, usePagination } from "."; import { useAddKeyToData, Table, useTranslation, usePagination } from ".";
import { DataTableProps } from "../../../types/Table"; import { DataTableProps } from "../../../types/Table";
import { useDataTableState } from "../../../zustand/TabState";
const NotFoundLottie = React.lazy( const NotFoundLottie = React.lazy(
() => import("../../../Components/Lottie/NotFound/NotFoundLottie"), () => import("../../../Components/Lottie/NotFound/NotFoundLottie"),
); );
@ -14,21 +15,26 @@ const DataTable: React.FC<DataTableProps> = ({
...props ...props
}) => { }) => {
const data: any[] = response?.data?.data || []; const data: any[] = response?.data?.data || [];
const dataSource = useAddKeyToData(data);
const columns = useColumns(); const columns = useColumns();
const { pagination, handlePageChange } = usePagination(response?.data); const { pagination, handlePageChange } = usePagination(response?.data);
const [t] = useTranslation(); const [t] = useTranslation();
const getRowClassName = (record: any, index: number): string => { const getRowClassName = (_record: any, index: number): string => {
return index % 2 === 0 ? "even-row" : "odd-row"; return index % 2 === 0 ? "even-row" : "odd-row";
}; };
const isRefetching = response?.isRefetching; const isRefetching = response?.isRefetching;
const isLoading = response?.isLoading; const isLoading = response?.isLoading;
const dataLength = data?.length ;
const {setDataTableLength} = useDataTableState()
useEffect(() => {
setDataTableLength(dataLength)
}, [dataLength])
return ( return (
<Table <Table
style={{ minHeight: "300px" }} style={{ minHeight: "300px" }}
columns={columns} columns={columns}
dataSource={dataSource} dataSource={data}
rowKey={"id"}
rowClassName={(record, index) => getRowClassName(record, index)} rowClassName={(record, index) => getRowClassName(record, index)}
className="DataTable" className="DataTable"
loading={{ loading={{

View File

@ -1,5 +1,4 @@
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import { PaginationAntd, PaginationMeta } from "../../types/Table"; import { PaginationAntd, PaginationMeta } from "../../types/Table";
import { useFilterStateState } from "../../zustand/Filter"; import { useFilterStateState } from "../../zustand/Filter";
@ -8,8 +7,6 @@ interface Data {
} }
const usePagination = (data: Data) => { const usePagination = (data: Data) => {
const navigate = useNavigate();
const location = useLocation();
const { Filter ,setFilter } = useFilterStateState(); const { Filter ,setFilter } = useFilterStateState();
const [pagination, setPagination] = useState<PaginationAntd>({ const [pagination, setPagination] = useState<PaginationAntd>({
@ -29,7 +26,6 @@ const usePagination = (data: Data) => {
}, [data]); }, [data]);
const handlePageChange = (page: number) => { const handlePageChange = (page: number) => {
// navigate(`?page=${page}`);
setFilter({ setFilter({
...Filter, ...Filter,
page:page page:page

View File

@ -17,7 +17,7 @@ const App: React.FC = () => {
sort_by sort_by
}); });
return <DataTable response={response} useColumns={useColumns} />; return <DataTable response={response} useColumns={useColumns} />;
}; };
export default App; export default App;

View File

@ -1,13 +1,10 @@
import { TableColumnsType } from "antd"; import { TableColumnsType } from "antd";
import { FaPlus } from "react-icons/fa";
import useModalHandler from "../../../utils/useModalHandler"; import useModalHandler from "../../../utils/useModalHandler";
import { ModalEnum } from "../../../enums/Model"; import { ModalEnum } from "../../../enums/Model";
import { useObjectToEdit } from "../../../zustand/ObjectToEditState"; import { useObjectToEdit } from "../../../zustand/ObjectToEditState";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { ABILITIES_ENUM } from "../../../enums/abilities";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { import {
canAddGrade,
canDeleteGrade, canDeleteGrade,
canEditGrade, canEditGrade,
canShowGrade, canShowGrade,
@ -15,7 +12,6 @@ import {
import ActionButtons from "../../../Components/Table/ActionButtons"; import ActionButtons from "../../../Components/Table/ActionButtons";
import ColumnsImage from "../../../Components/Columns/ColumnsImage"; import ColumnsImage from "../../../Components/Columns/ColumnsImage";
import { Grade } from "../../../types/Grade"; import { Grade } from "../../../types/Grade";
import { useFilterState } from "../../../Components/Utils/Filter/FilterState";
import { useFilterStateState } from "../../../zustand/Filter"; import { useFilterStateState } from "../../../zustand/Filter";
export const useColumns = () => { export const useColumns = () => {
@ -26,7 +22,7 @@ export const useColumns = () => {
const { setFilter } = useFilterStateState(); const { setFilter } = useFilterStateState();
const handelShow = (record: Grade) => { const handelShow = (record: Grade) => {
setFilter({}) setFilter({})
navigate(`${record?.id}`); navigate(`${record?.id}`);

View File

@ -11,7 +11,7 @@ const SelectTag: React.FC = () => {
const [fieldValue, setFieldValue] = useState<string>(""); const [fieldValue, setFieldValue] = useState<string>("");
const formik = useFormikContext<any>(); const formik = useFormikContext<any>();
const handleChange = (value: string[]) => { const handleChange = (value: string[]) => {
console.log(value); console.log(value,"value");
formik.setFieldValue("tags", value); formik.setFieldValue("tags", value);
setSearchValue(""); setSearchValue("");

View File

@ -115,7 +115,7 @@ const AddPage: React.FC = () => {
return false ; return false ;
} }
if(haveImageOrContent){ if(haveImageOrContent){
toast.error("validation.one_of_image_and_content_should_be_enter") toast.error(t("validation.one_of_image_and_content_should_be_enter"))
return false return false
} }
@ -127,8 +127,9 @@ const AddPage: React.FC = () => {
const haveAnswers = answers?.length > 0; const haveAnswers = answers?.length > 0;
const haveMoreThanOneAnswer = haveAnswers && answers?.length > 1; const haveMoreThanOneAnswer = haveAnswers && answers?.length > 1;
const haveOneAnswerRight = haveMoreThanOneAnswer && answers?.some((item: any) => item?.isCorrect === 1 || item.isCorrect === true); const haveOneAnswerRight = haveMoreThanOneAnswer && answers?.some((item: any) => item?.isCorrect === 1 || item.isCorrect === true);
const haveImageOrContent = haveOneAnswerRight && values?.answers?.some((item:any)=> !(item?.content) && !(item.content_image) ) const haveImageOrContent = haveOneAnswerRight && answers?.some((item:any)=> !(item?.content) && !(item.content_image) )
console.log(haveImageOrContent,"haveImageOrContent");
if (!haveAnswers) { if (!haveAnswers) {
toast.error(t("validation.it_should_have_more_than_one_answers")); toast.error(t("validation.it_should_have_more_than_one_answers"));
return false; return false;
@ -145,7 +146,7 @@ const AddPage: React.FC = () => {
} }
if(haveImageOrContent){ if(haveImageOrContent){
toast.error("validation.one_of_image_and_content_should_be_enter") toast.error(t("validation.one_of_image_and_content_should_be_enter"))
return false return false
} }

View File

@ -58,8 +58,7 @@ const EditPage: React.FC = () => {
const handleSubmit = (values: any) => { const handleSubmit = (values: any) => {
const DataToSend = structuredClone(values); const DataToSend = structuredClone(values);
setTagsSearch(null); setTagsSearch(null);
console.log(DataToSend);
if (isBseQuestion) { if (isBseQuestion) {
const UpdateBseQuestion = { const UpdateBseQuestion = {
id: DataToSend?.id, id: DataToSend?.id,
@ -89,6 +88,8 @@ const EditPage: React.FC = () => {
if (item?.id) { if (item?.id) {
const itemToSend = structuredClone(item); const itemToSend = structuredClone(item);
const keysToRemove = ["content_image"]; const keysToRemove = ["content_image"];
console.log(itemToSend,"itemToSend");
const updatedObject = removeStringKeys(itemToSend, keysToRemove); const updatedObject = removeStringKeys(itemToSend, keysToRemove);
console.log(updatedObject, "updatedObject"); console.log(updatedObject, "updatedObject");
@ -96,16 +97,6 @@ const EditPage: React.FC = () => {
const oldAnswers = [] as any; const oldAnswers = [] as any;
const newAnswers = [] as any; const newAnswers = [] as any;
if (updatedObject?.answers?.length > 0) {
const isValidAnswers = updatedObject?.answers?.some(
(answer: any) => answer?.isCorrect === 1,
);
// if(!isValidAnswers){
// toast.error(t("validation.at_least_one_answer_should_be_correct"));
// return;
// }
}
updatedObject?.answers?.forEach((item: any) => { updatedObject?.answers?.forEach((item: any) => {
if (item?.id) { if (item?.id) {
oldAnswers.push({ ...item, isCorrect: item?.isCorrect ? 1 : 0 }); oldAnswers.push({ ...item, isCorrect: item?.isCorrect ? 1 : 0 });
@ -118,7 +109,6 @@ const EditPage: React.FC = () => {
new: newAnswers, new: newAnswers,
}; };
console.log(answers); console.log(answers);
mutate({ mutate({
...updatedObject, ...updatedObject,
answers, answers,
@ -127,7 +117,10 @@ const EditPage: React.FC = () => {
} else { } else {
console.log(values?.id); console.log(values?.id);
const tags = processTags(DataToSend); const tags = processTags(item);
console.log(item,"DataToSend");
console.log(tags,"tags");
mutateAdd({ mutateAdd({
...item, ...item,
subject_id: subject_id, subject_id: subject_id,
@ -149,19 +142,17 @@ const EditPage: React.FC = () => {
const oldAnswers = [] as any; const oldAnswers = [] as any;
const newAnswers = [] as any; const newAnswers = [] as any;
if (updatedObject?.answers?.length > 0) {
// const isValidAnswers = updatedObject?.answers?.some((answer:any) => answer?.isCorrect === 1 || answer?.isCorrect === true)
// const isValidAnswers2 = updatedObject?.answers?.filter((answer: any) => answer?.isCorrect === 1 || answer?.isCorrect === true ).length > 1;
// console.log(isValidAnswers2);
// console.log(isValidAnswers,"isValidAnswers");
// if(!isValidAnswers || isValidAnswers2){
// toast.error(t("validation.at_least_one_answer_should_be_correct"));
// return;
// }
}
updatedObject?.answers?.forEach((item: any) => { updatedObject?.answers?.forEach((item: any) => {
if (item?.id) { if (item?.id) {
oldAnswers.push({ ...item, isCorrect: item?.isCorrect ? 1 : 0 }); console.log(item,"item");
const deletedImage = item?.content_image === null
if(deletedImage){
oldAnswers.push({ ...item, isCorrect: item?.isCorrect ? 1 : 0, content_image:"" });
}else{
oldAnswers.push({ ...item, isCorrect: item?.isCorrect ? 1 : 0 });
}
} else { } else {
newAnswers.push({ ...item, isCorrect: item?.isCorrect ? 1 : 0 }); newAnswers.push({ ...item, isCorrect: item?.isCorrect ? 1 : 0 });
} }
@ -181,7 +172,6 @@ const EditPage: React.FC = () => {
}; };
const location = useLocation(); const location = useLocation();
const navigate = useNavigate(); const navigate = useNavigate();
const handleCancel = () => { const handleCancel = () => {
navigate(-1); navigate(-1);
@ -191,6 +181,7 @@ const EditPage: React.FC = () => {
const handleValidateSingleQuestion = (values:any)=>{ const handleValidateSingleQuestion = (values:any)=>{
const haveMoreThanOneAnswer = values?.answers?.length > 1; const haveMoreThanOneAnswer = values?.answers?.length > 1;
const haveOneAnswerRight = haveMoreThanOneAnswer && values?.answers?.some((item:any)=> item?.isCorrect === 1 || item.isCorrect === true ) const haveOneAnswerRight = haveMoreThanOneAnswer && values?.answers?.some((item:any)=> item?.isCorrect === 1 || item.isCorrect === true )
const haveImageOrContent = haveOneAnswerRight && values?.answers?.some((item:any)=> !(item?.content) && !(item.content_image) )
if(!haveMoreThanOneAnswer){ if(!haveMoreThanOneAnswer){
toast.error(t("validation.it_should_have_more_than_one_answers")) ; toast.error(t("validation.it_should_have_more_than_one_answers")) ;
@ -200,6 +191,10 @@ const EditPage: React.FC = () => {
toast.error(t("validation.it_should_have_more_than_one_correct_answers")) ; toast.error(t("validation.it_should_have_more_than_one_correct_answers")) ;
return false ; return false ;
} }
if(haveImageOrContent){
toast.error(t("validation.one_of_image_and_content_should_be_enter"))
return false
}
} }
@ -210,6 +205,7 @@ const handleValidateBaseQuestion = (values: any) => {
const haveMoreThanOneAnswer = haveAnswers && answers?.length > 1; const haveMoreThanOneAnswer = haveAnswers && answers?.length > 1;
const haveOneAnswerRight = const haveOneAnswerRight =
haveMoreThanOneAnswer && answers?.some((item: any) => item?.isCorrect === 1 || item.isCorrect === true); haveMoreThanOneAnswer && answers?.some((item: any) => item?.isCorrect === 1 || item.isCorrect === true);
const haveImageOrContent = haveOneAnswerRight && answers?.some((item:any)=> !(item?.content) && !(item.content_image) )
if (!haveAnswers) { if (!haveAnswers) {
toast.error(t("validation.it_should_have_more_than_one_answers")); toast.error(t("validation.it_should_have_more_than_one_answers"));
@ -226,6 +222,12 @@ const handleValidateBaseQuestion = (values: any) => {
return false; return false;
} }
if(haveImageOrContent){
toast.error(t("validation.one_of_image_and_content_should_be_enter"))
return false
}
return true; return true;
}); });

View File

@ -9,11 +9,13 @@ import TextField from "./TextField";
import ImageBoxField from "../../../../../Components/CustomFields/ImageBoxField/ImageBoxField"; import ImageBoxField from "../../../../../Components/CustomFields/ImageBoxField/ImageBoxField";
import { GoTrash } from "react-icons/go"; import { GoTrash } from "react-icons/go";
import { Popconfirm } from "antd"; import { Popconfirm } from "antd";
import { useObjectToEdit } from "../../../../../zustand/ObjectToEditState";
const ChoiceFields = ({ index, data }: { index: number; data: Choice }) => { const ChoiceFields = ({ index, data }: { index: number; data: Choice }) => {
const formik = useFormikContext<any>(); const formik = useFormikContext<any>();
const [t] = useTranslation(); const [t] = useTranslation();
const { ShowHint } = useObjectToEdit();
const handleDeleteChoice = () => { const handleDeleteChoice = () => {
console.log(index); console.log(index);
@ -26,6 +28,16 @@ const ChoiceFields = ({ index, data }: { index: number; data: Choice }) => {
formik.setFieldValue("answers", updatedAnswers); formik.setFieldValue("answers", updatedAnswers);
}; };
const values = formik?.values?.answers?.[index] ;
const handelCanDeleteAnswers = ()=>{
const content = values?.content ;
const content_image = values?.content_image ;
if(!content && !content_image ){
return true
}
return false
}
return ( return (
<> <>
<div className="ChoiceFields"> <div className="ChoiceFields">
@ -52,32 +64,45 @@ const ChoiceFields = ({ index, data }: { index: number; data: Choice }) => {
name={index} name={index}
type="Checkbox" type="Checkbox"
/> />
{handelCanDeleteAnswers() ?
<p className="delete_question_options" onClick={()=>{handleDeleteChoice()}}>
{t("header.delete_choice")}
<GoTrash
className="trash_icon"
size={17}
/>
</p>
:
<Popconfirm <Popconfirm
title={t("header.this_will_un_do_all_your_changes")} title={t("header.this_will_un_do_all_your_changes")}
okText={t("practical.yes")} okText={t("practical.yes")}
cancelText={t("practical.no")} cancelText={t("practical.no")}
onConfirm={()=>{handleDeleteChoice()}} onConfirm={()=>{handleDeleteChoice()}}
defaultOpen={false} defaultOpen={false}
>
<p className="delete_question_options">
{t("header.delete_choice")}
<GoTrash
className="trash_icon"
size={17}
/>
</p>
>
</Popconfirm> <p className="delete_question_options">
{t("header.delete_choice")}
<GoTrash
className="trash_icon"
size={17}
/>
</p>
</Popconfirm>
}
</div> </div>
</div> </div>
<div className="exercise_form_width"> <div className="exercise_form_width">
{ShowHint &&
<ValidationField <ValidationField
className=" " className="hint"
placeholder="_" placeholder="_"
name={`answers.${index}.hint`} name={`answers.${index}.hint`}
label="hint" label="hint"
@ -86,6 +111,8 @@ const ChoiceFields = ({ index, data }: { index: number; data: Choice }) => {
showCount={false} showCount={false}
autoSize={{ minRows: 2, maxRows: 10 }} autoSize={{ minRows: 2, maxRows: 10 }}
/> />
}
</div> </div>
</> </>
); );

View File

@ -40,6 +40,8 @@ const Choices = () => {
{formik?.values?.answers?.map((item: Choice, index: number) => { {formik?.values?.answers?.map((item: Choice, index: number) => {
return ( return (
<div <div
key={index}
className="Choices"
> >
<ChoiceFields index={index} data={item} /> <ChoiceFields index={index} data={item} />
</div> </div>

View File

@ -10,6 +10,7 @@ import { toast } from "react-toastify";
import ImageBoxField from "../../../../../../Components/CustomFields/ImageBoxField/ImageBoxField"; import ImageBoxField from "../../../../../../Components/CustomFields/ImageBoxField/ImageBoxField";
import { GoTrash } from "react-icons/go"; import { GoTrash } from "react-icons/go";
import { Popconfirm } from "antd"; import { Popconfirm } from "antd";
import { useObjectToEdit } from "../../../../../../zustand/ObjectToEditState";
const ChoiceFields = ({ const ChoiceFields = ({
index, index,
@ -23,7 +24,7 @@ const ChoiceFields = ({
const formik = useFormikContext<any>(); const formik = useFormikContext<any>();
const [t] = useTranslation(); const [t] = useTranslation();
const { ShowHint } = useObjectToEdit();
const handleDeleteChoice = () => { const handleDeleteChoice = () => {
const arrayLength = formik.values.Questions?.[parent_index].answers?.length; const arrayLength = formik.values.Questions?.[parent_index].answers?.length;
@ -42,6 +43,19 @@ const ChoiceFields = ({
formik.setFieldValue(`Questions[${parent_index}].answers`, updatedAnswers); formik.setFieldValue(`Questions[${parent_index}].answers`, updatedAnswers);
}; };
const values = formik.values.Questions?.[parent_index]?.answers?.[index] ;
console.log(values,"values");
const handelCanDeleteAnswers = ()=>{
const content = values?.content ;
const content_image = values?.content_image ;
if(!content && !content_image ){
return true
}
return false
}
return ( return (
<> <>
<div className="ChoiceFields"> <div className="ChoiceFields">
@ -71,7 +85,19 @@ const ChoiceFields = ({
parent_index={parent_index} parent_index={parent_index}
/> />
<Popconfirm
{handelCanDeleteAnswers() ?
<p className="delete_question_options" onClick={()=>{handleDeleteChoice()}} >
{t("header.delete_choice")}
<GoTrash
className="trash_icon"
size={17}
/>
</p>
:
<Popconfirm
title={t("header.this_will_un_do_all_your_changes")} title={t("header.this_will_un_do_all_your_changes")}
okText={t("practical.yes")} okText={t("practical.yes")}
cancelText={t("practical.no")} cancelText={t("practical.no")}
@ -89,12 +115,17 @@ const ChoiceFields = ({
</p> </p>
</Popconfirm> </Popconfirm>
}
</div> </div>
</div> </div>
<div className="exercise_form_width"> <div className="exercise_form_width">
{ShowHint &&
<ValidationField <ValidationField
className=" " className="hint"
placeholder="_" placeholder="_"
name={`Questions.${parent_index}.answers.${index}.hint`} name={`Questions.${parent_index}.answers.${index}.hint`}
label="hint" label="hint"
@ -103,6 +134,8 @@ const ChoiceFields = ({
showCount={false} showCount={false}
autoSize={{ minRows: 2, maxRows: 10 }} autoSize={{ minRows: 2, maxRows: 10 }}
/> />
}
</div> </div>
</> </>
); );

View File

@ -52,7 +52,8 @@ const Choices = ({ parent_index }: { parent_index: number }) => {
).map((item: Choice, index: number) => { ).map((item: Choice, index: number) => {
return ( return (
<div <div
className="Choices ChoicesMalty"
key={index}
> >
<ChoiceFields <ChoiceFields
key={index} key={index}

View File

@ -16,14 +16,12 @@ import { toast } from "react-toastify";
const Form = () => { const Form = () => {
const formik = useFormikContext<any>(); const formik = useFormikContext<any>();
const { setSuccess, Success, setSavedQuestionData } = useObjectToEdit(); const { setSuccess, Success, setSavedQuestionData ,ShowHint} = useObjectToEdit();
useEffect(() => { useEffect(() => {
setSavedQuestionData(formik.values); setSavedQuestionData(formik.values);
}, [formik?.values]); }, [formik?.values]);
// console.log(formik?.errors);
const handleAddChoice = ( const handleAddChoice = (
parent_index: number, parent_index: number,
fromKeyCombination: boolean = false, fromKeyCombination: boolean = false,
@ -94,6 +92,11 @@ const Form = () => {
} }
}, [Success]); }, [Success]);
return ( return (
<Row className="w-100 exercise_form_container"> <Row className="w-100 exercise_form_container">
<div className="exercise_form"> <div className="exercise_form">
@ -113,7 +116,7 @@ const Form = () => {
(item: Choice, parent_index: number) => { (item: Choice, parent_index: number) => {
return ( return (
<div key={parent_index}> <div key={parent_index}>
<div className="exercise_form"> <div className="exercise_form QuestionFIeld">
<QuestionFIeld <QuestionFIeld
key={parent_index} key={parent_index}
index={parent_index} index={parent_index}
@ -135,6 +138,7 @@ const Form = () => {
)} )}
<div className="exercise_form_width"> <div className="exercise_form_width">
{ShowHint &&
<ValidationField <ValidationField
className=" " className=" "
placeholder="_" placeholder="_"
@ -145,6 +149,8 @@ const Form = () => {
autoSize={{ minRows: 2, maxRows: 10 }} autoSize={{ minRows: 2, maxRows: 10 }}
showCount={false} showCount={false}
/> />
}
<MaltySelectTag parent_index={parent_index} /> <MaltySelectTag parent_index={parent_index} />
</div> </div>
</div> </div>

View File

@ -29,6 +29,21 @@ const QuestionFIeld = ({ index, data }: { index: number; data: Choice }) => {
formik.setFieldValue(`Questions`, updatedAnswers); formik.setFieldValue(`Questions`, updatedAnswers);
}; };
const values = formik.values.Questions?.[index] ;
const handelCanDeleteAnswers = ()=>{
const content = values?.content ;
const content_image = values?.content_image ;
if(!content && !content_image ){
return true
}
return false
}
return ( return (
<> <>
<div className="exercise_forms"> <div className="exercise_forms">
@ -48,7 +63,22 @@ const QuestionFIeld = ({ index, data }: { index: number; data: Choice }) => {
<ImageBoxField name={`Questions.${index}.content_image`} /> <ImageBoxField name={`Questions.${index}.content_image`} />
<div className="answer_status" > {handelCanDeleteAnswers() ?
<div className="answer_status" >
<p className="delete_question_options" onClick={()=>{handleDeleteQuestion()}}>
{t("header.delete_question")}
<GoTrash
className="trash_icon"
size={17}
/>
</p>
</div>
:
<div className="answer_status" >
<Popconfirm <Popconfirm
title={t("header.this_will_un_do_all_your_changes")} title={t("header.this_will_un_do_all_your_changes")}
okText={t("practical.yes")} okText={t("practical.yes")}
@ -68,6 +98,9 @@ const QuestionFIeld = ({ index, data }: { index: number; data: Choice }) => {
</Popconfirm> </Popconfirm>
</div> </div>
}
</div> </div>
</div> </div>

View File

@ -10,7 +10,16 @@ const MaltySelectTag = ({ parent_index }: { parent_index: number }) => {
const [fieldValue, setFieldValue] = useState<string>(""); const [fieldValue, setFieldValue] = useState<string>("");
const formik = useFormikContext<any>(); const formik = useFormikContext<any>();
const values = formik?.values?.Questions?.[parent_index]?.tags; const values = formik?.values?.Questions?.[parent_index]?.tags;
const handleChange = (value: string[]) => { const [NewAdditionalData, setNewAdditionalData] = useState({})
const handleChange = (value: string[],option:any) => {
const newSelectedOption = option?.pop()
const newObject = {
id:newSelectedOption?.id,
name:newSelectedOption?.name
}
setNewAdditionalData(newObject)
formik.setFieldValue(`Questions.[${parent_index}].tags`, value); formik.setFieldValue(`Questions.[${parent_index}].tags`, value);
setSearchValue(""); setSearchValue("");
setFieldValue(""); setFieldValue("");
@ -40,14 +49,29 @@ const MaltySelectTag = ({ parent_index }: { parent_index: number }) => {
options.length < 1 && searchValue.length > 1 && !isLoading options.length < 1 && searchValue.length > 1 && !isLoading
? [{ id: searchValue, name: searchValue }] ? [{ id: searchValue, name: searchValue }]
: []; : [];
const value = const value =
formik?.values?.Questions[parent_index]?.tags?.map( formik?.values?.Questions[parent_index]?.tags?.map(
(item: any) => item?.id ?? item, (item: any) => item?.id ?? item,
) ?? []; ) ?? [];
const AllOptions = [...options, ...additionalData];
const initialData = formik?.values?.Questions[parent_index]?.tags?.filter((item:any)=>{
return item?.id
}) ?? []
const AllOptions = [...options, ...additionalData,NewAdditionalData , ...(initialData)];
const uniqueOptions = Array.from(
new Map(
AllOptions
.filter(item => Object.keys(item).length > 0) // Filter out empty objects
.map(item => [item.id, item]) // Create [id, item] pairs to ensure uniqueness
).values()
);
return ( return (
<div className="SelectTag"> <div className="SelectTag">
<label htmlFor="">{t("models.tag")}</label> <label htmlFor="">{t("models.tag")}</label>
@ -58,7 +82,7 @@ const MaltySelectTag = ({ parent_index }: { parent_index: number }) => {
placeholder="" placeholder=""
fieldNames={{ label: "name", value: "id" }} fieldNames={{ label: "name", value: "id" }}
onChange={handleChange} onChange={handleChange}
options={AllOptions} options={uniqueOptions}
filterOption={false} filterOption={false}
loading={isLoading} loading={isLoading}
notFoundContent={isLoading ? <Spin /> : t("practical.not_found")} notFoundContent={isLoading ? <Spin /> : t("practical.not_found")}

View File

@ -16,7 +16,7 @@ import { toast } from "react-toastify";
const Form = () => { const Form = () => {
const [t] = useTranslation(); const [t] = useTranslation();
const formik = useFormikContext<any>(); const formik = useFormikContext<any>();
const { setSuccess, Success } = useObjectToEdit(); const { setSuccess, Success,ShowHint } = useObjectToEdit();
const handleAddChoice = (fromKeyCombination: boolean = false) => { const handleAddChoice = (fromKeyCombination: boolean = false) => {
formik.setFieldValue("answers", [ formik.setFieldValue("answers", [
@ -68,7 +68,9 @@ const Form = () => {
</p> </p>
)} )}
<div className="exercise_form_width"> <div className="exercise_form_width">
{ShowHint &&
<ValidationField <ValidationField
className=" " className=" "
placeholder="_" placeholder="_"
@ -80,6 +82,8 @@ const Form = () => {
autoSize={{ minRows: 2, maxRows: 10 }} autoSize={{ minRows: 2, maxRows: 10 }}
/> />
}
<SelectTag /> <SelectTag />
</div> </div>
</Row> </Row>

View File

@ -51,7 +51,6 @@ const TableHeader = () => {
{name:LessonName, path:`lesson/${lesson_id }`} {name:LessonName, path:`lesson/${lesson_id }`}
]); ]);
return ( return (
<div className="TableWithHeader"> <div className="TableWithHeader">
<Suspense fallback={<Spin />}> <Suspense fallback={<Spin />}>

View File

@ -1,6 +1,5 @@
import * as Yup from "yup"; 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 => { export const getInitialValues = (objectToEdit: Question): any => {
const tags = objectToEdit?.tags?.map((item: any, index: number) => { const tags = objectToEdit?.tags?.map((item: any, index: number) => {
@ -60,7 +59,6 @@ export const getInitialValuesBase = (objectToEdit: Question): any => {
} }
}) })
console.log(newAnswers,"newAnswers");
return { return {
...item, ...item,
@ -123,6 +121,7 @@ export const getValidationSchemaBase = () => {
export function processTags(DataToSend: any) { export function processTags(DataToSend: any) {
console.log(DataToSend?.tags); console.log(DataToSend?.tags);
console.log(DataToSend);
const oldTags = DataToSend?.tags const oldTags = DataToSend?.tags
?.map((item: any, index: number) => { ?.map((item: any, index: number) => {

View File

@ -7,14 +7,16 @@ import { handelImageState } from "../../../../utils/DataToSendImageState";
import LayoutModel from "../../../../Layout/Dashboard/LayoutModel"; import LayoutModel from "../../../../Layout/Dashboard/LayoutModel";
import { QueryStatusEnum } from "../../../../enums/QueryStatus"; import { QueryStatusEnum } from "../../../../enums/QueryStatus";
import ModelForm from "./ModelForm"; import ModelForm from "./ModelForm";
import { useParams } from "react-router-dom";
import { ParamsEnum } from "../../../../enums/params";
const ModalForm: React.FC = () => { const ModalForm: React.FC = () => {
const { objectToEdit } = useObjectToEdit((state) => state); const { objectToEdit } = useObjectToEdit((state) => state);
const { mutate, status } = useUpdateSubject(); const { mutate, status } = useUpdateSubject();
const {subject_id} = useParams<ParamsEnum>()
const handleSubmit = (values: any) => { const handleSubmit = (values: any) => {
const Data_to_send = { ...values }; const Data_to_send = { ...values,subject_id };
const handelImage = handelImageState(Data_to_send, "icon"); const handelImage = handelImageState(Data_to_send, "icon");
mutate(handelImage); mutate(handelImage);
}; };

View File

@ -1,6 +1,7 @@
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import useFilter from "../../Components/FilterField/components/useFilter"; import useFilter from "../../Components/FilterField/components/useFilter";
import { Select } from "antd";
const Dummy = () => { const Dummy = () => {
const [t] = useTranslation(); const [t] = useTranslation();
@ -8,12 +9,15 @@ const Dummy = () => {
return ( return (
<div className="DummyHomePage"> <div className="DummyHomePage">
<FilterButton/> {/* <FilterButton/>
<FilterBody> <FilterBody>
karim karim
</FilterBody> </FilterBody>
<Select
karim2 style={{width:"200px"}}
showSearch
/> */}
</div> </div>
); );
}; };

View File

@ -1,7 +1,7 @@
.filter_header { .filter_header {
padding: 20px 20px; padding: 20px 20px;
border-radius: 10px 10px 0 0; border-radius: 10px 10px 0 0;
box-shadow: 2px 2px 7px 2px rgba(0, 0, 0, 0.1); box-shadow: 0px 0px 32px 2px #080F3414;
>div { >div {
display: flex; display: flex;
@ -105,15 +105,3 @@
.model_sub_children { .model_sub_children {
padding-bottom: 30px; padding-bottom: 30px;
} }
.ant-select-selection-search {
// color: var(--value) !important;
// display: none !important;
}
:where(.css-dev-only-do-not-override-oad6qy).ant-select-single.ant-select-lg .ant-select-selector .ant-select-selection-search {
input {}
}
:where(.css-dev-only-do-not-override-oad6qy).ant-select-single.ant-select-lg:not(.ant-select-customize-input) .ant-select-selector .ant-select-selection-search-input {}

View File

@ -3,6 +3,7 @@
@import "./Layout.scss"; @import "./Layout.scss";
@import "./SideBar.scss"; @import "./SideBar.scss";
@import "./DataTable.scss"; @import "./DataTable.scss";
@import "./DataState.scss"; @import "./DataState.scss";
@import "./PageHeader.scss"; @import "./PageHeader.scss";
@import "./FilterLayout.scss"; @import "./FilterLayout.scss";

View File

@ -133,6 +133,7 @@
.exercise_add_header { .exercise_add_header {
display: flex; display: flex;
gap: 30px;
justify-content: space-between; justify-content: space-between;
width: 100%; width: 100%;
padding: 14px 20px; padding: 14px 20px;
@ -142,6 +143,7 @@
box-shadow: 0px 0px 4px 2px rgba(0, 0, 0, 0.1); box-shadow: 0px 0px 4px 2px rgba(0, 0, 0, 0.1);
div{ div{
margin-left: 25px; margin-left: 25px;
display: flex;
} }
img { img {
cursor: pointer; cursor: pointer;
@ -262,4 +264,49 @@
font-weight: bold; font-weight: bold;
font-size: 19px; font-size: 19px;
} }
}
.Choices{
padding-inline: 20px;
.textarea_exercise,.hint{
width: calc(50vw - 10px) !important;
}
.ValidationField{
.text{
font-size: 14px;
}
}
}
.QuestionFIeld{
padding-inline: 10px;
.textarea_exercise{
width: calc(50vw - 10px) !important;
}
.ValidationField{
.text{
font-size: 17px;
}
}
}
.Choices.ChoicesMalty{
.textarea_exercise,.hint{
width: calc(50vw - 20px) !important;
}
.ValidationField{
.text{
font-size: 14px;
}
}
}
.question_header_setting{
margin-inline: 40px;
} }

View File

@ -31,7 +31,7 @@ function useAxios() {
const build_Axios = buildAxios.build(); const build_Axios = buildAxios.build();
build_Axios.interceptors.response.use( build_Axios.interceptors.response.use(
function (response: any) { function (response: any) {
const responseMsg = response?.data?.message; const responseMsg = response?.data?.message;
const method = response.config.method; const method = response.config.method;
@ -53,7 +53,7 @@ function useAxios() {
console.log(error?.response); console.log(error?.response);
const status = error?.request?.status; const status = error?.request?.status;
const errorMsg = error?.response?.data?.message; const errorMsg = error?.response?.data?.error;
const errorField = error?.response?.data; const errorField = error?.response?.data;
const method = error.config.method; const method = error.config.method;

View File

@ -2,6 +2,8 @@ import { useMutation, UseMutationResult } from "react-query";
import useAxios from "./useAxios"; import useAxios from "./useAxios";
import { HEADER_KEY } from "../config"; import { HEADER_KEY } from "../config";
import { AxiosResponse } from "../../types/Axios"; import { AxiosResponse } from "../../types/Axios";
import { useDataTableState } from "../../zustand/TabState";
import { useFilterStateState } from "../../zustand/Filter";
type DataToSend = { type DataToSend = {
id?: number | string | any; id?: number | string | any;
@ -14,8 +16,12 @@ function useDeleteMutation(
toast: boolean = true, toast: boolean = true,
): UseMutationResult<AxiosResponse, unknown, DataToSend, unknown> { ): UseMutationResult<AxiosResponse, unknown, DataToSend, unknown> {
const axios = useAxios(); const axios = useAxios();
const {DataTableLength} = useDataTableState()
const { setFilter ,Filter } = useFilterStateState();
const page = Filter?.page ;
return useMutation<AxiosResponse, unknown, DataToSend, unknown>( return useMutation<AxiosResponse, unknown, DataToSend, unknown>(
async (dataToSend) => { async (dataToSend) => {
const { data } = await axios.delete(url + `/` + dataToSend?.id, { const { data } = await axios.delete(url + `/` + dataToSend?.id, {
headers: { headers: {
[HEADER_KEY]: key, [HEADER_KEY]: key,
@ -25,7 +31,21 @@ function useDeleteMutation(
return data; return data;
}, },
); {
onSuccess : (data) =>{
if(DataTableLength === 1 && page > 1){
setFilter(
{
...Filter,
page: page - 1
}
)
}
}
}
)
} }
export default useDeleteMutation; export default useDeleteMutation;

View File

@ -1,7 +1,5 @@
import { useQuery } from "react-query"; import { useQuery } from "react-query";
import useAxios from "./useAxios"; import useAxios from "./useAxios";
import { useLocation } from "react-router-dom";
import { PaginationParams } from "../utils/PaginationParams";
import { filterParams } from "../utils/filterParams"; import { filterParams } from "../utils/filterParams";
import { useFilterStateState } from "../../zustand/Filter"; import { useFilterStateState } from "../../zustand/Filter";
function useGetQuery( function useGetQuery(
@ -13,11 +11,9 @@ function useGetQuery(
const axios = useAxios(); const axios = useAxios();
const { show, pagination, ...remainingParams } = params; const { show, pagination, ...remainingParams } = params;
const location = useLocation(); const { Filter } = useFilterStateState();
const { Filter ,setFilter } = useFilterStateState();
const page = Filter?.page ; const page = Filter?.page ;
const per_page = Filter?.per_page ; const per_page = Filter?.per_page ;
// const { per_page } = PaginationParams(location);
const paramToSend = pagination const paramToSend = pagination

View File

@ -49,7 +49,8 @@
"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_answers": "يجب أن يحتوي على أكثر من إجابة",
"it_should_have_more_than_one_correct_answers": "يجب أن يحتوي على إجابة صحيحة", "it_should_have_more_than_one_correct_answers": "يجب أن يحتوي على إجابة صحيحة",
"File_size_exceeds_2_MB_limit.":"حجم الملف يتجاوز الحد الأقصى البالغ 2 ميجابايت" "File_size_exceeds_2_MB_limit.":"حجم الملف يتجاوز الحد الأقصى البالغ 2 ميجابايت",
"one_of_image_and_content_should_be_enter":"يجب إدخال صورة أو محتوى واحد على الأقل"
}, },
"header": { "header": {
"register_students": "تسجيل الطلاب", "register_students": "تسجيل الطلاب",
@ -138,7 +139,9 @@
"change": "تغيير", "change": "تغيير",
"role_list": "قائمة الأدوار", "role_list": "قائمة الأدوار",
"managers":"مدراء", "managers":"مدراء",
"sales":"المبيعات" "sales":"المبيعات",
"hide_hint":"اخفاء الشرح",
"show_hint":"عرض الشرح"
}, },
"columns": { "columns": {
"id": "الرقم التعريفي", "id": "الرقم التعريفي",

View File

@ -14,7 +14,7 @@ export function removeStringKeys(obj: any, keysToRemove: string[]): any {
// Check if the value is a string or "null" and the key is in keysToRemove // Check if the value is a string or "null" and the key is in keysToRemove
if ( if (
keysToRemove.includes(key) && keysToRemove.includes(key) &&
(typeof value === "string" || value === "null") (typeof value === "string")
) { ) {
delete obj[key]; delete obj[key];
} else { } else {

View File

@ -24,10 +24,13 @@ interface ModelState {
SavedQuestionData: any; SavedQuestionData: any;
setSavedQuestionData: (data: any) => void; setSavedQuestionData: (data: any) => void;
ShowHint: any;
setShowHint: (data: any) => void;
} }
export const useObjectToEdit = create<ModelState>((set) => ({ export const useObjectToEdit = create<ModelState>((set) => ({
c: null, objectToEdit: null,
setObjectToEdit: (data) => set(() => ({ objectToEdit: data })), setObjectToEdit: (data) => set(() => ({ objectToEdit: data })),
OldObjectToEdit: null, OldObjectToEdit: null,
setOldObjectToEdit: (data) => set(() => ({ OldObjectToEdit: data })), setOldObjectToEdit: (data) => set(() => ({ OldObjectToEdit: data })),
@ -49,4 +52,6 @@ export const useObjectToEdit = create<ModelState>((set) => ({
setDeletedQuestions: (data) => set(() => ({ DeletedQuestions: data })), setDeletedQuestions: (data) => set(() => ({ DeletedQuestions: data })),
SavedQuestionData: [], SavedQuestionData: [],
setSavedQuestionData: (data) => set(() => ({ SavedQuestionData: data })), setSavedQuestionData: (data) => set(() => ({ SavedQuestionData: data })),
ShowHint: true,
setShowHint: (data) => set(() => ({ ShowHint: data })),
})); }));

12
src/zustand/TabState.ts Normal file
View File

@ -0,0 +1,12 @@
import { create } from "zustand";
interface DataTableState {
DataTableLength: number;
setDataTableLength: (Key: number) => void;
}
export const useDataTableState = create<DataTableState>((set) => ({
DataTableLength: 0,
setDataTableLength: (Key) => set((state) => ({ DataTableLength: Key })),
}));