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", "typescript": "^4.9.5",
"vite": "^5.4.8", "vite": "^5.4.8",
"vite-plugin-compression": "^0.5.1", "vite-plugin-compression": "^0.5.1",
"vite-plugin-env-compatible": "^2.0.1",
"webpack": "^5.95.0", "webpack": "^5.95.0",
"webpack-cli": "^5.1.4" "webpack-cli": "^5.1.4"
} }
@ -5275,6 +5276,23 @@
"csstype": "^3.0.2" "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": { "node_modules/ejs": {
"version": "3.1.10", "version": "3.1.10",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz",
@ -14656,6 +14674,17 @@
"vite": ">=2.0.0" "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": { "node_modules/void-elements": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
@ -18867,6 +18896,18 @@
"csstype": "^3.0.2" "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": { "ejs": {
"version": "3.1.10", "version": "3.1.10",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz",
@ -25325,6 +25366,16 @@
"fs-extra": "^10.0.0" "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": { "void-elements": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",

View File

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

View File

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

View File

@ -23,6 +23,7 @@ const SearchField = ({
canChangePage, canChangePage,
PageName, PageName,
page, page,
clear,
...props ...props
}: SearchFieldProps) => { }: SearchFieldProps) => {
const { errorMsg, isError, t, formik } = useFormField(name, props); 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 handleScroll = (event: any) => {
const target = event.target; const target = event.target;
const isAtBottom = const isAtBottom =

View File

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

View File

@ -24,6 +24,10 @@ export type SelectFieldProps = BaseFieldProps &
canChangePage?: boolean; canChangePage?: boolean;
PageName?: string; PageName?: string;
page?: number; page?: number;
clear?:{
method:(value:boolean) => void,
value: boolean,
}
}; };
export type SearchFieldProps = BaseFieldProps & export type SearchFieldProps = BaseFieldProps &
@ -36,6 +40,10 @@ export type SearchFieldProps = BaseFieldProps &
canChangePage: boolean; canChangePage: boolean;
PageName: string; PageName: string;
page: number; page: number;
clear?:{
method:(value:boolean) => void,
value: boolean,
}
}; };
type DateFieldProps = BaseFieldProps & { 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 { t } = useTranslation();
const translateArray = translateOptions(search_array, t); const translateArray = translateOptions(search_array, t);
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const isMultiSearch :boolean = search_by.split(" ").length > 1
const { FilterBody, FilterSubmit } = useFilter(); const { FilterBody, FilterSubmit } = useFilter();
return ( return (
@ -74,7 +75,14 @@ const FilterLayout = ({
</span> </span>
<div className="header_search"> <div className="header_search">
{haveSearch && ( {isMultiSearch ?
search_by.split(" ").map(searchBy =>
<SearchField
searchBy={searchBy}
placeholder={t(`practical.${searchBy}`)}
/>
)
: haveSearch && (
<SearchField <SearchField
searchBy={search_by} searchBy={search_by}
placeholder={t("practical.search_here")} placeholder={t("practical.search_here")}

View File

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

View File

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

View File

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

View File

@ -44,7 +44,7 @@ export const useColumns = () => {
// console.log(grade,"grade"); // console.log(grade,"grade");
setFilter({}); // setFilter({});
navigate( 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}`, `/${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": "المستخدمون" "notifiable_type": "المستخدمون"
}, },
"practical": { "practical": {
"content":"السؤال",
"hasAnswer":"الجواب",
"hasRightAnswer":"الجواب الصحيح",
"to_confirm_deletion_please_re_enter": "لتأكيد الحذف، يرجى إعادة الإدخال", "to_confirm_deletion_please_re_enter": "لتأكيد الحذف، يرجى إعادة الإدخال",
"back": "العودة", "back": "العودة",
"add": "إضافة", "add": "إضافة",