This commit is contained in:
Majd_dk 2025-07-27 14:42:18 +03:00
parent f9d87ebb0f
commit 1e83413544
14 changed files with 279 additions and 88 deletions

51
package-lock.json generated
View File

@ -68,6 +68,7 @@
"typescript": "^4.9.5",
"vite": "^5.4.8",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-env-compatible": "^2.0.1",
"webpack": "^5.95.0",
"webpack-cli": "^5.1.4"
}
@ -5275,6 +5276,23 @@
"csstype": "^3.0.2"
}
},
"node_modules/dotenv": {
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
"integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==",
"dev": true,
"license": "BSD-2-Clause",
"engines": {
"node": ">=8"
}
},
"node_modules/dotenv-expand": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
"integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==",
"dev": true,
"license": "BSD-2-Clause"
},
"node_modules/ejs": {
"version": "3.1.10",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz",
@ -14656,6 +14674,17 @@
"vite": ">=2.0.0"
}
},
"node_modules/vite-plugin-env-compatible": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/vite-plugin-env-compatible/-/vite-plugin-env-compatible-2.0.1.tgz",
"integrity": "sha512-DRrOZTg/W44ojVQQfGSMPEgYQGzp5TeIpt9cpaK35hTOC/b2D7Ffl8/RIgK8vQ0mlnDIUgETcA173bnMEkyzdw==",
"dev": true,
"license": "MIT",
"dependencies": {
"dotenv": "8.2.0",
"dotenv-expand": "5.1.0"
}
},
"node_modules/void-elements": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
@ -18867,6 +18896,18 @@
"csstype": "^3.0.2"
}
},
"dotenv": {
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
"integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==",
"dev": true
},
"dotenv-expand": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
"integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==",
"dev": true
},
"ejs": {
"version": "3.1.10",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz",
@ -25325,6 +25366,16 @@
"fs-extra": "^10.0.0"
}
},
"vite-plugin-env-compatible": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/vite-plugin-env-compatible/-/vite-plugin-env-compatible-2.0.1.tgz",
"integrity": "sha512-DRrOZTg/W44ojVQQfGSMPEgYQGzp5TeIpt9cpaK35hTOC/b2D7Ffl8/RIgK8vQ0mlnDIUgETcA173bnMEkyzdw==",
"dev": true,
"requires": {
"dotenv": "8.2.0",
"dotenv-expand": "5.1.0"
}
},
"void-elements": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",

View File

@ -89,6 +89,7 @@
"typescript": "^4.9.5",
"vite": "^5.4.8",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-env-compatible": "^2.0.1",
"webpack": "^5.95.0",
"webpack-cli": "^5.1.4"
}

View File

@ -10,11 +10,11 @@ interface Props {
}
const SearchField: React.FC<Props> = ({ placeholder, searchBy }) => {
const { setFilter, Filter } = useFilterStateState();
const [isOpen, setIsOpen] = useState(false);
const [searchQuery, setSearchQuery] = useState<string>("");
const [searchQuery, setSearchQuery] = useState<string>(Filter[searchBy] || "");
const inputRef = useRef<HTMLInputElement>(null);
const { setFilter, Filter } = useFilterStateState();
const { page } = PaginationParams(location);
const handleInputChange = (value: string) => {
@ -25,6 +25,7 @@ const SearchField: React.FC<Props> = ({ placeholder, searchBy }) => {
if (Number(page) > 1) {
}
setFilter({
...Filter,
[searchBy]: value,
});
});
@ -46,6 +47,7 @@ const SearchField: React.FC<Props> = ({ placeholder, searchBy }) => {
};
}, []);
console.log(searchQuery)
const [t] = useTranslation();
return (
<div className={`search-field ${isOpen ? "open" : ""}`}>

View File

@ -23,6 +23,7 @@ const SearchField = ({
canChangePage,
PageName,
page,
clear,
...props
}: SearchFieldProps) => {
const { errorMsg, isError, t, formik } = useFormField(name, props);
@ -92,6 +93,14 @@ const SearchField = ({
}
};
// to clear
useEffect(()=>{
if(clear?.value){
formik.setFieldValue(name, null)
clear?.method?.(false)
}
},[clear?.value])
const handleScroll = (event: any) => {
const target = event.target;
const isAtBottom =

View File

@ -1,5 +1,5 @@
import { Select } from "antd";
import React from "react";
import React, { useEffect } from "react";
import useFormField from "../../../Hooks/useFormField";
import { translateOptions } from "../utils/translatedOptions";
import { ValidationFieldLabel } from "../components/ValidationFieldLabel";
@ -18,6 +18,7 @@ const SelectField = ({
no_label,
label_icon,
isLoading,
clear,
...props
}: SelectFieldProps) => {
const { errorMsg, isError, t, formik } = useFormField(name, props);
@ -29,6 +30,13 @@ const SelectField = ({
};
const options = translateOptions(option, t);
// to clear
useEffect(()=>{
if(clear?.value){
formik.setFieldValue(name, null)
clear?.method?.(false)
}
},[clear?.value])
return (
<div className="ValidationField w-100">
<ValidationFieldLabel

View File

@ -24,6 +24,10 @@ export type SelectFieldProps = BaseFieldProps &
canChangePage?: boolean;
PageName?: string;
page?: number;
clear?:{
method:(value:boolean) => void,
value: boolean,
}
};
export type SearchFieldProps = BaseFieldProps &
@ -36,6 +40,10 @@ export type SearchFieldProps = BaseFieldProps &
canChangePage: boolean;
PageName: string;
page: number;
clear?:{
method:(value:boolean) => void,
value: boolean,
}
};
type DateFieldProps = BaseFieldProps & {

View File

@ -0,0 +1,54 @@
import React from "react";
import { disapledDependsOn } from "./handles";
export type children = {
defaultValue?:any
dependensValue: number | string | undefined | Array<any> | any;
props:{[key:string]:any}
};
export type parent = {
defaultValue?:any,
props:{[key:string]:any}
};
type DependensesFieldesProps = {
parent?: parent;
childrens?: children[];
Component: React.ComponentType<any>;
};
function DependensesFieldes({
parent,
childrens,
Component,
}: DependensesFieldesProps) {
return (
<>
{parent && React.createElement(Component, {
...{...parent.props},
...(parent.defaultValue && { defaultValue: parent.defaultValue }),
})}
{childrens?.map((child: children, index: number) =>
React.createElement(Component, {
key: index,
...{...child.props},
...(child.defaultValue
? {
defaultValue: child.defaultValue,
clear: disapledDependsOn(child.dependensValue)
? { value: disapledDependsOn(child.dependensValue) }
: undefined,
}
: { clear: { value: disapledDependsOn(child.dependensValue) } }),
disabled:disapledDependsOn(child.dependensValue),
})
)}
</>
);
}
export default DependensesFieldes;

View File

@ -0,0 +1,11 @@
export const disapledDependsOn =(value:any) =>{
let status = false
if (!value || (Array.isArray(value) && value.length === 0)) {
return true;
}
else if(Array.isArray(value)){
value.filter((item) => disapledDependsOn(item) ).length > 0 ? status = true:''
}
return status
}

View File

@ -31,6 +31,7 @@ const FilterLayout = ({
const { t } = useTranslation();
const translateArray = translateOptions(search_array, t);
const [isOpen, setIsOpen] = useState(false);
const isMultiSearch :boolean = search_by.split(" ").length > 1
const { FilterBody, FilterSubmit } = useFilter();
return (
@ -74,7 +75,14 @@ const FilterLayout = ({
</span>
<div className="header_search">
{haveSearch && (
{isMultiSearch ?
search_by.split(" ").map(searchBy =>
<SearchField
searchBy={searchBy}
placeholder={t(`practical.${searchBy}`)}
/>
)
: haveSearch && (
<SearchField
searchBy={search_by}
placeholder={t("practical.search_here")}

View File

@ -8,6 +8,7 @@ import { useGetAllUnit } from "../../../../api/unit";
import { useGetAllSubject } from "../../../../api/subject";
import { useGetAllLesson } from "../../../../api/lesson";
import { useGetAllTag } from "../../../../api/tags";
import DependensesFieldes from "../../../../Components/dependensesFields/DependensesFields";
const FilterForm = () => {
const { ValidationParamState } = useValidationValidationParamState();
@ -23,10 +24,17 @@ const FilterForm = () => {
TagName,
TagCurrentPage,
} = ValidationParamState;
const formik :any= useFormikContext()
const grade_id = formik.values.grade_id?.id
const subject_id = formik.values?.subject_id?.id
const unit_id = formik.values?.unit_id?.id
const lessonsIds = formik.values?.lessonsIds?.map((lesson:any) => lesson.id)
const { data: Grade, isLoading: isLoadingGrade } = useGetAllGrade({
name: GradeName,
page: GradeCurrentPage,
page: GradeCurrentPage,
});
const GradeOption = Grade?.data ?? [];
const canChangeGradePage = !!Grade?.links?.next;
@ -36,7 +44,12 @@ const FilterForm = () => {
const { data: Subject, isLoading: isLoadingSubject } = useGetAllSubject({
name: SubjectName,
page: SubjectCurrentPage,
});
grade_id
},
{
enabled: !!grade_id
}
);
const SubjectOption = Subject?.data ?? [];
const canChangeSubjectPage = !!Subject?.links?.next;
const SubjectPage = Subject?.meta?.current_page;
@ -45,7 +58,14 @@ const FilterForm = () => {
const { data: Unit, isLoading: isLoadingUnit } = useGetAllUnit({
name: UnitName,
page: UnitCurrentPage,
});
grade_id,
subject_id
},
{
enabled: !!grade_id || !!subject_id
}
);
const UnitOption = Unit?.data ?? [];
const canChangeUnitPage = !!Unit?.links?.next;
const UnitPage = Unit?.meta?.current_page;
@ -54,106 +74,120 @@ const FilterForm = () => {
const { data: Lesson, isLoading: isLoadingLesson } = useGetAllLesson({
name: LessonName,
page: LessonCurrentPage,
});
grade_id,
unit_id
},
{
enabled: !!grade_id || !!unit_id
}
);
const LessonOption = Lesson?.data ?? [];
const canChangeLessonPage = !!Lesson?.links?.next;
const LessonPage = Lesson?.meta?.current_page;
const LessonPage = Lesson?.meta?.current_page;
/// TagsIds
const { data: Tag, isLoading: isLoadingTag } = useGetAllTag({
name: TagName,
page: TagCurrentPage,
lessonsIds,
grade_id,
subject_id,
unit_id
});
const TagOption = Tag?.data ?? [];
const canChangeTagPage = !!Tag?.links?.next;
const TagPage = Tag?.meta?.current_page;
const colRight:any = [
{
props: {
searchBy: "GradeName",
name: "grade_id",
label: "grade",
type: "Search",
option: GradeOption,
isLoading: isLoadingGrade,
canChangePage: canChangeGradePage,
PageName: "GradeCurrentPage",
page: GradePage,
}
},
{
dependensValue:grade_id,
props: {
searchBy: "SubjectName",
name: "subject_id",
label: "subject",
type: "Search",
option: SubjectOption,
isLoading: isLoadingSubject,
canChangePage: canChangeSubjectPage,
PageName: "SubjectCurrentPage",
page: SubjectPage,
},
},
{
dependensValue:subject_id,
props: {
searchBy: "UnitName",
name: "unit_id",
label: "unit",
type: "Search",
option: UnitOption,
isLoading: isLoadingUnit,
canChangePage: canChangeUnitPage,
PageName: "UnitCurrentPage",
page: UnitPage,
},
},
];
const colLeft :any=[
{
dependensValue: unit_id,
props: {
searchBy: "LessonName",
name: "lessonsIds",
label: "lesson",
type: "Search",
option: LessonOption,
isMulti: true,
isLoading: isLoadingLesson,
canChangePage: canChangeLessonPage,
PageName: "LessonCurrentPage",
page: LessonPage,
},
},
{
dependensValue: "none" ,
props: {
searchBy: "TagName",
name: "tagsIds",
label: "tag",
type: "Search",
option: TagOption,
isMulti: true,
isLoading: isLoadingTag,
canChangePage: canChangeTagPage,
PageName: "TagCurrentPage",
page: TagPage,
},
}
]
console.log(formik.values)
return (
<div>
<Row>
<Col>
{/*
grade_id
*/}
<ValidationField
searchBy="GradeName"
name="grade_id"
label="grade"
type="Search"
option={GradeOption}
isLoading={isLoadingGrade}
canChangePage={canChangeGradePage}
PageName={"GradeCurrentPage"}
page={GradePage}
/>
<DependensesFieldes parent={colRight[0]} Component={ValidationField} childrens={colRight.slice(1)}/>
{/*
subject_id
*/}
<ValidationField
searchBy="SubjectName"
name="subject_id"
label="subject"
type="Search"
option={SubjectOption}
isLoading={isLoadingSubject}
canChangePage={canChangeSubjectPage}
PageName={"SubjectCurrentPage"}
page={SubjectPage}
/>
{/*
TagsIds
*/}
<ValidationField
searchBy="TagName"
name="tagsIds"
label="tag"
type="Search"
option={TagOption}
isMulti
isLoading={isLoadingTag}
canChangePage={canChangeTagPage}
PageName={"TagCurrentPage"}
page={TagPage}
/>
</Col>
<Col>
{/*
unit_id
*/}
<ValidationField
searchBy="UnitName"
name="unit_id"
label="unit"
type="Search"
option={UnitOption}
isLoading={isLoadingUnit}
canChangePage={canChangeUnitPage}
PageName={"UnitCurrentPage"}
page={UnitPage}
/>
{/*
lessonsIds
*/}
<ValidationField
searchBy="LessonName"
name="lessonsIds"
label="lesson"
type="Search"
option={LessonOption}
isMulti
isLoading={isLoadingLesson}
canChangePage={canChangeLessonPage}
PageName={"LessonCurrentPage"}
page={LessonPage}
/>
<DependensesFieldes Component={ValidationField} childrens={colLeft}/>
</Col>
</Row>
</div>

View File

@ -32,7 +32,7 @@ const TableHeader = () => {
/>
<FilterLayout
width="700px"
search_by="content"
search_by="content hasAnswer hasRightAnswer"
sub_children={<FilterForm />}
filterTitle="table.QuestionBank"
/>

View File

@ -23,6 +23,8 @@ const App: React.FC = () => {
unit_id: filterState?.unit_id?.id,
lessonsIds: ConvertArrayToArrayOfIds(filterState?.lessonsIds),
content: Filter?.content,
hasAnswer: Filter?.hasAnswer,
hasRightAnswer: Filter?.hasRightAnswer,
sort_by,
});

View File

@ -44,7 +44,7 @@ export const useColumns = () => {
// console.log(grade,"grade");
setFilter({});
// setFilter({});
navigate(
`/${ABILITIES_ENUM?.GRADE}/${grade?.id}/${ABILITIES_ENUM?.SUBJECT}/${subject?.id}/${ABILITIES_ENUM?.UNIT}/${unit?.id}/${ABILITIES_ENUM?.LESSON}/${lesson?.id}/${ABILITIES_ENUM?.QUESTION}/${record?.id}`,
);

View File

@ -252,6 +252,9 @@
"notifiable_type": "المستخدمون"
},
"practical": {
"content":"السؤال",
"hasAnswer":"الجواب",
"hasRightAnswer":"الجواب الصحيح",
"to_confirm_deletion_please_re_enter": "لتأكيد الحذف، يرجى إعادة الإدخال",
"back": "العودة",
"add": "إضافة",