Compare commits

..

No commits in common. "b873ac0bba800e8764b4195fb8127bbe3dc161ca" and "f5e0bebeb026bb43ae9639b74927f9a2664af2a8" have entirely different histories.

222 changed files with 8592 additions and 7416 deletions

File diff suppressed because one or more lines are too long

View File

@ -5,8 +5,18 @@
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<link rel="apple-touch-icon" sizes="180x180" href="/App/Logo.png" /> <link rel="apple-touch-icon" sizes="180x180" href="/App/Logo.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/App/Logo.png" /> <link
<link rel="icon" type="image/png" sizes="16x16" href="/App/Logo.png" /> rel="icon"
type="image/png"
sizes="32x32"
href="/App/Logo.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="/App/Logo.png"
/>
<link rel="manifest" href="/site.webmanifest" /> <link rel="manifest" href="/site.webmanifest" />
<meta <meta
name="description" name="description"

View File

@ -1,7 +1,6 @@
{ {
"name": "my-app", "name": "my-app",
"version": "0.1.0", "version": "0.1.0",
"type": "module",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@ant-design/icons": "^5.3.7", "@ant-design/icons": "^5.3.7",

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -17,7 +17,7 @@ const App = () => {
const { changeLanguage } = useChangeLanguage(); const { changeLanguage } = useChangeLanguage();
const navigate = useNavigate(); const navigate = useNavigate();
const { isAuthenticated } = useAuthState(); const { isAuthenticated } = useAuthState();
const [t] = useTranslation(); const [t] = useTranslation()
useEffect(() => { useEffect(() => {
if (!isAuthenticated) { if (!isAuthenticated) {
@ -26,14 +26,7 @@ const App = () => {
}, [isAuthenticated, navigate]); }, [isAuthenticated, navigate]);
const renderRouteElement = (route: any) => ( const renderRouteElement = (route: any) => (
<Suspense <Suspense fallback={<Layout> <SpinContainer/> </Layout>}>
fallback={
<Layout>
{" "}
<SpinContainer />{" "}
</Layout>
}
>
{route.header ? ( {route.header ? (
<Layout>{route.element}</Layout> <Layout>{route.element}</Layout>
) : ( ) : (
@ -42,11 +35,11 @@ const App = () => {
</Suspense> </Suspense>
); );
const renderRoutesRecursively = (routes: TMenuItem[]) => const renderRoutesRecursively = (routes:TMenuItem[]) =>
routes.map((route: TMenuItem) => { routes.map((route: TMenuItem) => {
const useAbility = hasAbility(route.abilities, route.abilities_value); const useAbility = hasAbility(route.abilities, route.abilities_value);
const tableHeader = t(`${route?.header}`); const tableHeader = t(`${route?.header}`);
// useSetPageTitle(tableHeader,route?.path); // useSetPage_title(tableHeader,route?.path);
if (useAbility) { if (useAbility) {
return ( return (
@ -87,7 +80,7 @@ const App = () => {
{CrudRoute.map((route) => { {CrudRoute.map((route) => {
const useAbility = hasAbility(route.abilities, route.abilities_value); const useAbility = hasAbility(route.abilities, route.abilities_value);
const tableHeader = t(`${route?.header}`); const tableHeader = t(`${route?.header}`);
// useSetPageTitle(tableHeader,route?.path); // useSetPage_title(tableHeader,route?.path);
if (!useAbility) { if (!useAbility) {
return false; return false;

View File

@ -0,0 +1,58 @@
import React, { useEffect, useRef, useState } from "react";
import ReactApexChart from "react-apexcharts";
const AreaChart: React.FC = () => {
const chartRef = useRef<any>(null); // Ref for the chart component
const [options, setOptions] = useState<any>({
chart: {
type: "area",
toolbar: {
show: false, // Disable the toolbar
},
},
dataLabels: {
enabled: false,
},
stroke: {
curve: "smooth",
},
xaxis: {
type: "datetime",
categories: [
"2018-09-19T00:00:00.000Z",
"2018-09-19T01:30:00.000Z",
"2018-09-19T02:30:00.000Z",
"2018-09-19T03:30:00.000Z",
"2018-09-19T04:30:00.000Z",
"2018-09-19T05:30:00.000Z",
"2018-09-19T06:30:00.000Z",
],
},
tooltip: {
x: {
format: "dd/MM/yy HH:mm",
},
},
});
const [series, setSeries] = useState<any>([
{ name: "series1", data: [31, 40, 28, 51, 42, 109, 100], color: "#FCC43E" },
{ name: "series2", data: [11, 32, 45, 32, 34, 52, 41], color: "#FB7D5B" },
]);
return (
<div className="AreaChart">
<div id="chart">
<ReactApexChart
options={options}
series={series}
type="area"
className="ReactApexChartArea"
height={400}
/>
</div>
<div id="html-dist"></div>
</div>
);
};
export default AreaChart;

View File

@ -0,0 +1,95 @@
import { Radio, Select } from "antd";
import React, { useState } from "react";
import ReactApexChart from "react-apexcharts";
import { IoMdArrowDropdown } from "react-icons/io";
const ColumnChart: React.FC = () => {
const series = [
{
name: "غياب",
data: [44, 55, 57, 56, 61, 58],
color: "#FB7D5B",
},
{
name: "حضور",
data: [76, 85, 70, 98, 87, 80],
color: "#FCC43E",
},
];
const options: any = {
chart: {
type: "bar",
},
plotOptions: {
bar: {
horizontal: false,
columnWidth: "35%",
endingShape: "rounded",
},
},
dataLabels: {
enabled: false,
},
xaxis: {
categories: ["Feb", "Mar", "Apr", "May", "Jun", "Jul"],
},
// yaxis: {
// title: {
// text: '$ (thousands)'
// }
// },
fill: {
opacity: 1,
colors: ["#FB7D5B", "#FCC43E"], // Red and Green colors
},
tooltip: {
y: {
formatter: function (val: number) {
return val + " طالب";
},
},
},
legend: {
show: false, // Hide the legend
},
};
const [value, setValue] = useState(1);
const handleChangeSelect = (value: string) => {};
return (
<div className="ColumnChart">
<div className="ColumnChart_header">
<span>الغياب المتكرر</span>
<span className="Legend">
<div data-attr="red">غياب</div>
<div>حضور</div>
</span>
<Select
defaultValue="هذا الأسبوع"
onChange={handleChangeSelect}
suffixIcon={<IoMdArrowDropdown size={30} />}
options={[
{ value: "هذا الأسبوع", label: "هذا الأسبوع" },
{ value: "هذا الأسبوع", label: "هذا الأسبوع" },
{ value: "هذا الأسبوع", label: "هذا الأسبوع" },
]}
/>
</div>
<div className="ColumnChartWrapper" id="chart">
<ReactApexChart
options={options}
series={series}
type="bar"
height={"100%"}
/>
</div>
<div id="html-dist"></div>
</div>
);
};
export default ColumnChart;

View File

@ -0,0 +1,61 @@
import React from "react";
import Chart from "react-apexcharts";
const LineChart: React.FC = () => {
const series = [
{
name: "Desktops",
data: [10, 41, 35, 51, 49, 62, 69, 91, 148],
},
];
const options: any = {
chart: {
height: 350,
type: "line",
zoom: {
enabled: false,
},
},
dataLabels: {
enabled: false,
},
stroke: {
curve: "straight",
},
title: {
text: "Product Trends by Month",
align: "left",
},
grid: {
row: {
colors: ["#f3f3f3", "transparent"], // takes an array which will be repeated on columns
opacity: 0.5,
},
},
xaxis: {
categories: [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
],
},
};
return (
<div>
<div id="chart">
<Chart options={options} series={series} type="line" height={350} />
</div>
<div id="html-dist"></div>
</div>
);
};
export default LineChart;

View File

@ -0,0 +1,38 @@
import React from "react";
import Chart from "react-apexcharts";
const PieChart = () => {
const series = [44, 55, 13] as any;
const options: any = {
series: [44, 55, 13],
chart: {
width: 380,
type: "pie",
},
labels: ["Team A", "Team B", "Team C", "Team D", "Team E"],
legend: {
position: "bottom",
},
responsive: [
{
breakpoint: 480,
options: {
chart: {
width: 200,
},
legend: {
position: "bottom",
},
},
},
],
};
return (
<div id="chart">
<Chart options={options} series={series} type="pie" width={380} />
</div>
);
};
export default PieChart;

View File

@ -0,0 +1,14 @@
import React from "react";
import { Segmented } from "antd";
const ClassesSegmented: React.FC = () => (
<Segmented<string>
options={["الأحد", "اللإثنين", "الثلاثاء", "الأربعاء", "الخميس"]}
onChange={(value) => {}}
className="Segmented"
block
defaultChecked
/>
);
export default ClassesSegmented;

View File

@ -0,0 +1,105 @@
import React, { useState } from "react";
import { FaPlus, FaUser } from "react-icons/fa";
import { IoMdArrowDropdown, IoMdArrowDropup } from "react-icons/io";
import { useNavigate } from "react-router-dom";
import { Popover, Spin } from "antd";
import { CourseItem } from "../../types/Item";
import { ModalEnum } from "../../enums/Model";
import useModalHandler from "../../utils/useModalHandler";
import { FaEllipsis } from "react-icons/fa6";
import { ABILITIES_ENUM, ABILITIES_VALUES_ENUM } from "../../enums/abilities";
import { hasAbility } from "../../utils/hasAbility";
import { useTranslation } from "react-i18next";
const HeaderCardsSection = ({ data, isLoading }: any) => {
const [showAll, setShowAll] = useState<boolean>(false);
const [t] = useTranslation();
const toggleShowAll = () => {
setShowAll(!showAll);
};
const navigate = useNavigate();
const index_eduClass_ability = hasAbility(
ABILITIES_ENUM?.EDUCATION_CLASS,
ABILITIES_VALUES_ENUM?.INDEX,
);
const handelnavigate = (item: CourseItem) => {
if (index_eduClass_ability) {
navigate(
`/${ABILITIES_ENUM?.COURSE}/${item?.id}/${ABILITIES_ENUM?.EDUCATION_CLASS}`,
);
// set_title(item?.name);
}
};
const { handel_open_model } = useModalHandler();
const Courses = data?.data || [];
if (isLoading) {
return <Spin />;
}
const PopoverContent = (
<div className="PopoverContent">
<p onClick={() => handel_open_model(ModalEnum?.COURSE_ADD)}>
{" "}
{t("practical.add")} {t("models.course")} <FaPlus />{" "}
</p>
</div>
);
const store_course_ability = hasAbility(
ABILITIES_ENUM?.COURSE,
ABILITIES_VALUES_ENUM?.STORE,
);
return (
<div className="header_cards_section">
<div className="CountCards">
{Courses?.length > 0 &&
Courses?.map((item: CourseItem, index: number) => {
return (
<div
onClick={() => handelnavigate(item)}
key={item?.id}
className={`CountCard ${!showAll && index >= 6 ? "hidden" : ""}`}
>
<i>
<FaUser />
</i>
<h4>{item?.name}</h4>
<h5>
{item?.student_count} {t("models.student")}{" "}
</h5>
</div>
);
})}
</div>
{Courses?.length > 4 &&
(showAll ? (
<span className="Show_More_Button" onClick={toggleShowAll}>
<IoMdArrowDropup />
</span>
) : (
<span className="Show_More_Button" onClick={toggleShowAll}>
<IoMdArrowDropdown />
</span>
))}
{store_course_ability && (
<Popover
content={PopoverContent}
overlayClassName="Popover"
arrow={false}
placement="bottomRight"
trigger={"click"}
>
<FaEllipsis />
</Popover>
)}
</div>
);
};
export default HeaderCardsSection;

View File

@ -0,0 +1,67 @@
import React, { useState } from "react";
import { useModalState } from "../../zustand/Modal";
import { ModalEnum } from "../../enums/Model";
import { FaMoneyBill } from "react-icons/fa";
import { IoMdArrowDropdown, IoMdArrowDropup } from "react-icons/io";
const DivisionsHeaderSection = () => {
const [showAll, setShowAll] = useState<boolean>(false);
const toggleShowAll = () => {
setShowAll(!showAll);
};
const { isOpen, setIsOpen } = useModalState((state) => state);
const handelOpenModal = () => {
setIsOpen(ModalEnum?.DIVISION_ADD);
};
// Define the interface for your data
interface Item {
icon: JSX.Element;
name: string;
}
const data: Item[] = [
{ icon: <FaMoneyBill />, name: "الطالبات" },
{ icon: <FaMoneyBill />, name: "الطالبات" },
{ icon: <FaMoneyBill />, name: "الطالبات" },
{ icon: <FaMoneyBill />, name: "الطالبات" },
{ icon: <FaMoneyBill />, name: "الطالبات" },
{ icon: <FaMoneyBill />, name: "الطالبات" },
{ icon: <FaMoneyBill />, name: "الطالبات" },
{ icon: <FaMoneyBill />, name: "الطالبات" },
];
return (
<div className="Divisions_header_section">
<div className="CountCards">
{data?.map((item: Item, index: number) => {
return (
<div
key={index}
className={`CountCard ${!showAll && index >= 5 ? "hidden" : ""}`}
>
<i>{item?.icon}</i>
<h4>{item?.name}</h4>
</div>
);
})}
</div>
{showAll ? (
<span className="Show_More_Button" onClick={toggleShowAll}>
<IoMdArrowDropup />
</span>
) : (
<span className="Show_More_Button" onClick={toggleShowAll}>
<IoMdArrowDropdown />
</span>
)}
<button className="Add_button" onClick={handelOpenModal}>
إضافة مادة
</button>
</div>
);
};
export default DivisionsHeaderSection;

View File

@ -0,0 +1,128 @@
import React, { useState } from "react";
import { ModalEnum } from "../../enums/Model";
import { FaPlus, FaUser } from "react-icons/fa";
import { IoMdArrowDropdown, IoMdArrowDropup } from "react-icons/io";
import { FaEllipsis } from "react-icons/fa6";
import { Popover, Spin } from "antd";
import { useGetAllEduClass } from "../../api/eduClass";
import { useNavigate, useParams } from "react-router-dom";
import { EduClassItem } from "../../types/Item";
import useModalHandler from "../../utils/useModalHandler";
import { usePage_titleState } from "../../zustand/PageTitleState";
import { hasAbility } from "../../utils/hasAbility";
import { ABILITIES_ENUM, ABILITIES_VALUES_ENUM } from "../../enums/abilities";
import { useTranslation } from "react-i18next";
const HeaderSection = () => {
const [showAll, setShowAll] = useState<boolean>(false);
const toggleShowAll = () => {
setShowAll(!showAll);
};
const { course_id } = useParams();
const { data, isLoading } = useGetAllEduClass({ course_id: course_id });
const eduClass = data?.data || [];
const { set_title } = usePage_titleState((state) => state);
const { handel_open_model } = useModalHandler();
const navigate = useNavigate();
const show_eduClass_ability = hasAbility(
ABILITIES_ENUM?.EDUCATION_CLASS,
ABILITIES_VALUES_ENUM?.SHOW,
);
const handelNavigate = (item: EduClassItem) => {
if (show_eduClass_ability) {
navigate(`${item?.id}`);
set_title(`${item?.name}`);
}
};
const [t] = useTranslation();
const store_eduClass_ability = hasAbility(
ABILITIES_ENUM?.EDUCATION_CLASS,
ABILITIES_VALUES_ENUM?.STORE,
);
const delete_course_ability = hasAbility(
ABILITIES_ENUM?.COURSE,
ABILITIES_VALUES_ENUM?.DELETE,
);
const store_note_ability = hasAbility(
ABILITIES_ENUM?.NOTE,
ABILITIES_VALUES_ENUM?.STORE,
);
const PopoverContent = (
<div className="PopoverContent">
{store_eduClass_ability && (
<p onClick={() => handel_open_model(ModalEnum?.EDUClASS_ADD)}>
{" "}
{t("practical.add")} {t("models.education_class")} <FaPlus />{" "}
</p>
)}
{store_note_ability && (
<p
onClick={() => handel_open_model(ModalEnum?.COURSE_SENDNOTIFICATION)}
>
{" "}
{t("practical.Send_Direct_Notification")}
</p>
)}
{delete_course_ability && (
<p onClick={() => handel_open_model(ModalEnum?.COURSE_DELETE)}>
{" "}
{t("practical.delete")} {t("models.course")}
</p>
)}
</div>
);
if (isLoading) {
return <Spin />;
}
return (
<div className="header_cards_section">
<div className="CountCards">
{eduClass?.map((item: EduClassItem, index: number) => {
return (
<div
onClick={() => handelNavigate(item)}
key={index}
className={`CountCard ${!showAll && index >= 6 ? "hidden" : ""}`}
>
<i>
<FaUser />
</i>
<h4>{item?.name}</h4>
<h5>
{item?.students_count} {t("models.student")}{" "}
</h5>
</div>
);
})}
</div>
{eduClass?.length > 4 &&
(showAll ? (
<span className="Show_More_Button" onClick={toggleShowAll}>
<IoMdArrowDropup />
</span>
) : (
<span className="Show_More_Button" onClick={toggleShowAll}>
<IoMdArrowDropdown />
</span>
))}
<Popover
content={PopoverContent}
overlayClassName="Popover"
arrow={false}
placement="bottomRight"
>
<FaEllipsis />
</Popover>
</div>
);
};
export default HeaderSection;

View File

@ -0,0 +1,103 @@
import React, { useState } from "react";
import { ModalEnum } from "../../enums/Model";
import { FaUser } from "react-icons/fa";
import { IoMdArrowDropdown, IoMdArrowDropup } from "react-icons/io";
import { FaEllipsis } from "react-icons/fa6";
import { Popover } from "antd";
import { useLocation, useNavigate } from "react-router-dom";
import { Item } from "../../types/Item";
import useModalHandler from "../../utils/useModalHandler";
import { useButtonState } from "../../zustand/ButtonState";
import { useObjectToEdit } from "../../zustand/ObjectToEditState";
import { useTranslation } from "react-i18next";
import { ABILITIES_VALUES_ENUM } from "../../enums/abilities";
// import useSetPage_title from "../../Hooks/useSetPageTitle";
import { EduClassComponents } from "../../Pages/EduClass/show/ActiveTable";
import { hasAbility } from "../../utils/hasAbility";
const HeaderSection = () => {
const [showAll, setShowAll] = useState<boolean>(true);
const toggleShowAll = () => {
setShowAll(!showAll);
};
const [t] = useTranslation();
// useSetPage_title(
// `${t(ABILITIES_ENUM?.MAIN_PAGE)} / ${t(`models.${ABILITIES_ENUM.COURSE}`)} / ${t(`models.${ABILITIES_ENUM.EDUCATION_CLASS}`)} / ${t(`input.details`)}`,
// );
const { handel_open_model } = useModalHandler();
const filteredComponents = EduClassComponents?.filter((component) =>
hasAbility(component.abilities, ABILITIES_VALUES_ENUM.INDEX),
);
const PopoverContent = (
<div className="PopoverContent">
<p
onClick={() => handel_open_model(ModalEnum?.EDUClASS_SENDNOTIFICATION)}
>
{" "}
{t("practical.Send_Direct_Notification")}
</p>
<p onClick={() => handel_open_model(ModalEnum?.EDUClASS_DELETE)}>
{" "}
{t("practical.delete")} {t("models.education_class")}
</p>
</div>
);
const [, setActiveButton] = useState(0);
const { setActiveTab, ActiveTab } = useButtonState((state) => state);
const { setParamToSend } = useObjectToEdit();
const location = useLocation();
const navigate = useNavigate();
const handleButtonClick = (index: number) => {
setActiveButton(index);
setActiveTab(index);
setParamToSend({});
navigate(`${location.pathname}`);
};
return (
<div className="header_cards_section">
<div className="CountCards">
{filteredComponents?.map((item: Item, index: number) => {
return (
<div
key={index}
onClick={() => handleButtonClick(index)}
className={`CountCard ${!showAll && index >= 6 ? "hidden" : ""} ${ActiveTab === index ? "active" : ""} `}
>
<i>
<FaUser />
</i>
<h4> {t(`education_class_actions.${item?.name}`)} </h4>
</div>
);
})}
</div>
{filteredComponents?.length > 4 &&
(showAll ? (
<span className="Show_More_Button" onClick={toggleShowAll}>
<IoMdArrowDropup />
</span>
) : (
<span className="Show_More_Button" onClick={toggleShowAll}>
<IoMdArrowDropdown />
</span>
))}
<Popover
content={PopoverContent}
overlayClassName="Popover"
arrow={false}
placement="bottomRight"
>
<FaEllipsis />
</Popover>
</div>
);
};
export default HeaderSection;

View File

@ -0,0 +1,21 @@
import { Col, Row } from "reactstrap";
import React from "react";
import ValidationField from "../../../../ValidationField/ValidationField";
const AttachmentsDetails = () => {
return (
<Row xs={1} sm={1} md={1} lg={2} xl={2}>
<Col xs="6" sm="6">
<ValidationField
name="attachment1"
type="DropFile"
label="school_document"
/>
{/* <ValidationField name='attachment2' type='DropFile' label='الوثيقة'/> */}
</Col>
<Col xs="6" sm="6"></Col>
</Row>
);
};
export default AttachmentsDetails;

View File

@ -0,0 +1,36 @@
import { Col, Row } from "reactstrap";
import React from "react";
import ValidationField from "../../../../ValidationField/ValidationField";
const ContactDetails = () => {
return (
<div className="bigRow">
<ValidationField
type="number"
name="phone_number_1"
label="phone_number"
/>
<ValidationField
type="number"
name="phone_number_2"
label="additional_phone_number"
/>
<ValidationField
type="TextArea"
name="address"
label="address"
placeholder="address"
/>
<ValidationField
type="TextArea"
name="notes"
label="note"
placeholder="note"
/>
</div>
);
};
export default ContactDetails;

View File

@ -0,0 +1,34 @@
import { Col, Row } from "reactstrap";
import React, { useRef } from "react";
import ValidationField from "../../../../ValidationField/ValidationField";
const ParentDetails = () => {
const handelClick = () => {};
return (
<div className="bigRow">
<ValidationField name="father_name" label="father_name" />
<ValidationField name="father_job" label="father_job" />
<ValidationField
type="number"
name="father_phone_number"
label="father_phone_number"
/>
<ValidationField name="mother_name" label="mother_name" />
<ValidationField name="mother_job" label="mother_job" />
<ValidationField
type="number"
name="mother_phone_number"
label="mother_phone_number"
/>
{/* <Col xs="8" sm="8">
</Col> */}
</div>
);
};
export default ParentDetails;

View File

@ -0,0 +1,72 @@
import { Col, Row } from "reactstrap";
import React from "react";
import ValidationField from "../../../../ValidationField/ValidationField";
import {
Sex_Select_options_Student,
nationalities,
religion_Select_options,
} from "../../../../../types/App";
const PersonalDetails = () => {
return (
<Row>
<Col xs="8" sm="8">
<ValidationField name="email" label="email" />
<div className="TowValidationItems">
<ValidationField name="first_name" label="first_name" />
<ValidationField name="last_name" label="last_name" />
</div>
<div className="TowValidationItems">
<ValidationField name="username" label="username" />
<ValidationField name="password" label="password" />
</div>
<div className="TowValidationItems">
<ValidationField
name="nationality"
type="LocalSearch"
option={nationalities}
label="nationality"
placeholder="nationality"
/>
<ValidationField
name="religion"
type="Select"
option={religion_Select_options}
no_label
placeholder="religion"
/>
</div>
<div className="TowValidationItems">
<ValidationField
name="birthday"
type="Date"
label="birthday"
placeholder="birthday"
/>
<ValidationField
name="birth_place"
no_label
placeholder="birth_place"
/>
</div>
<ValidationField
name="sex"
label="sex"
type="Select"
option={Sex_Select_options_Student}
placeholder="sex"
/>
</Col>
<Col xs="4" sm="4">
<ValidationField name="image" type="DropFile" label="image" />
</Col>
</Row>
);
};
export default PersonalDetails;

View File

@ -0,0 +1,46 @@
import React from "react";
import Image from "../../../../Ui/Image";
import { useModalTabsState } from "../../../../../zustand/ModalTabsState";
import { useModalState } from "../../../../../zustand/Modal";
import { useFormikContext } from "formik";
import { useTranslation } from "react-i18next";
const Successful = () => {
const { setActiveTab } = useModalTabsState((state) => state);
const { setIsOpen } = useModalState((state) => state);
const formik = useFormikContext<any>();
const [t] = useTranslation();
return (
<div className="AddedSuccessfully">
<Image src="/DataState/successfully.png" />
<h1> {t("header.Student_added_successfully")} </h1>
<p>
{t(
"header.the_student_has_been_added_Do_you_want_to_add_another_student",
)}
</p>
<div className="TowButton">
<button
onClick={() => {
setActiveTab(0);
formik?.resetForm();
}}
>
{t("header.Add_a_new_student")}
</button>
<button
onClick={() => {
setIsOpen("");
setActiveTab(0);
formik?.resetForm();
}}
>
{t("practical.skip")}
</button>
</div>
</div>
);
};
export default Successful;

View File

@ -0,0 +1,80 @@
import React, { useEffect } from "react";
import { Modal } from "antd";
import { useModalState } from "../../../../../zustand/Modal";
import FormikForm from "../../../../../Layout/Dashboard/FormikForm";
import ModelBody from "./ModelBody";
import TabsSubmite from "./TabsSubmite";
import { getInitialValues, getValidationSchema } from "./formUtil";
import { ModalEnum } from "../../../../../enums/Model";
import { useAddStudent } from "../../../../../api/student";
import { useParams } from "react-router-dom";
import { useModalTabsState } from "../../../../../zustand/ModalTabsState";
const ModalForm: React.FC = () => {
const { isOpen, setIsOpen } = useModalState((state) => state);
const { mutate, isSuccess, isLoading } = useAddStudent();
const { edu_class_id } = useParams();
const handleSubmit = (values: any) => {
const Data_To_Send = { ...values };
delete Data_To_Send["id"];
Data_To_Send.attachments = [];
if (Data_To_Send.attachment1 !== null) {
Data_To_Send.attachments.push({
name: "attachment1",
file: Data_To_Send.attachment1,
});
}
if (Data_To_Send.attachment2 !== null) {
Data_To_Send.attachments.push({
name: "attachment2",
file: Data_To_Send.attachment2,
});
}
Data_To_Send["edu_class_id"] = edu_class_id;
Data_To_Send["birthday"] = values.birthday?.format(
"YYYY-MM-DD HH:mm:ss.SSS",
);
if (!values?.attachment1) {
delete Data_To_Send["attachments"];
}
// console.log(Data_To_Send);
mutate(Data_To_Send);
};
const { setActiveTab } = useModalTabsState((state) => state);
useEffect(() => {
if (isSuccess) {
setActiveTab(4);
getInitialValues([]);
}
}, [isSuccess, setActiveTab]);
return (
<>
<Modal
className="AddModalForm"
centered
width={"80vw"}
footer={null}
open={isOpen === ModalEnum.STUDENT_ADD}
onOk={() => setIsOpen("")}
onCancel={() => setIsOpen("")}
>
<FormikForm
handleSubmit={handleSubmit}
initialValues={getInitialValues([])}
validationSchema={getValidationSchema}
>
<ModelBody />
<TabsSubmite isLoading={isLoading} steps={4} />
</FormikForm>
</Modal>
</>
);
};
export default ModalForm;

View File

@ -0,0 +1,67 @@
import PersonalDetails from "../Form/PersonalDetails";
import TabsBar from "../../../../Layout/Tabs/TabsBar";
import ActiveTabs from "../../../../Layout/Tabs/ActiveTabs";
import { usePage_titleState } from "../../../../../zustand/PageTitleState";
import ParentDetails from "../Form/ParentDetails";
import ContactDetails from "../Form/ContactDetails";
import AttachmentsDetails from "../Form/AttachmentsDetails";
import Successful from "../Form/Successful";
import { useModalState } from "../../../../../zustand/Modal";
import { useFormikContext } from "formik";
import { useEffect } from "react";
import { useTranslation } from "react-i18next";
const ModelBody = () => {
const { title } = usePage_titleState((state) => state);
const [t] = useTranslation();
const steps = [
{
title: `${t(`practical.Step`)} 1`,
description: t("header.Student_Information"),
component: <PersonalDetails />,
},
{
title: `${t(`practical.Step`)} 2`,
description: t("header.Parent_Information"),
component: <ParentDetails />,
},
{
title: `${t(`practical.Step`)} 3`,
description: t("header.Contact_Information"),
component: <ContactDetails />,
},
{
title: `${t(`practical.Step`)} 4`,
description: t("header.Attachment_Images"),
component: <AttachmentsDetails />,
},
{
title: "hidden",
description: "hidden",
hidden: true,
component: <Successful />,
},
];
const { isOpen } = useModalState((state) => state);
const formik = useFormikContext();
useEffect(() => {
formik.setErrors({});
}, [isOpen === ""]);
return (
<div className="ModelBody">
<TabsBar steps={steps} />
<div className="ModelBodyForm">
<header>
{" "}
{t("practical.add")} {t("models.student")}{" "}
{" " + title === null ? "" : title}{" "}
</header>
<ActiveTabs steps={steps} />
</div>
</div>
);
};
export default ModelBody;

View File

@ -0,0 +1,128 @@
import React, { useEffect } from "react";
import { useModalTabsState } from "../../../../../zustand/ModalTabsState";
import { useModalState } from "../../../../../zustand/Modal";
import { useFormikContext } from "formik";
import { toast } from "react-toastify";
import { Spin } from "antd";
import { useTranslation } from "react-i18next";
interface TabsSubmiteProps {
steps: number;
isLoading: boolean;
}
const TabsSubmite: React.FC<TabsSubmiteProps> = ({ steps, isLoading }) => {
const { values, isValid, submitForm } = useFormikContext<any>();
const { ActiveTab, setActiveTab } = useModalTabsState((state) => state);
const IsSubmite = ActiveTab + 1 !== steps;
const {
first_name,
last_name,
username,
password,
nationality,
religion,
birthday,
birth_place,
sex,
} = values;
const {
father_name,
father_job,
father_phone_number,
mother_name,
mother_job,
mother_phone_number,
} = values;
const { address, attachment1 } = values;
const is_1_valued =
first_name &&
username &&
last_name &&
password &&
nationality &&
religion &&
birthday &&
birth_place &&
sex;
const is_2_valued =
father_name &&
father_job &&
father_phone_number &&
mother_name &&
mother_job &&
mother_phone_number;
const is_3_valued = address;
const is_4_valued = attachment1;
const [t] = useTranslation();
function handelNext() {
// console.log("submited");
// console.log(isValid,"isValid");
if (!is_1_valued && Number(ActiveTab) === 0) {
toast.error(t("validation.pleas_fill_all_label"));
return;
}
if (!is_2_valued && Number(ActiveTab) === 1) {
toast.error(t("validation.pleas_fill_all_label"));
return;
}
if (!is_3_valued && Number(ActiveTab) === 2) {
toast.error(t("validation.pleas_fill_all_label"));
return;
}
if (!is_4_valued && Number(ActiveTab) === 3) {
toast.error(t("validation.pleas_fill_all_label"));
return;
}
if (Number(ActiveTab) >= steps) {
return;
}
setActiveTab(Number(ActiveTab) + 1);
}
function handelPre() {
setActiveTab(Number(ActiveTab) - 1);
}
const handleSubmit = () => {
if (isValid) {
submitForm();
} else {
submitForm();
// console.log('Validation errors:', formik.errors);
// setActiveTab(4)
toast.error(t("validation.pleas_fill_all_label"));
}
};
// console.log(ActiveTab,"ActiveTab");
if (ActiveTab === steps) {
return <></>;
}
return (
<div className="SubmitButton">
<div onClick={handelPre}>
{ActiveTab > 0 ? "رجوع للخطوة السابقة" : ""}
</div>
<span
onClick={isLoading ? undefined : IsSubmite ? handelNext : handleSubmit}
{...(!IsSubmite && !isLoading ? { type: "submit" } : {})}
>
{isLoading
? "جار الاضافة ...."
: IsSubmite
? "الخطوة التالية"
: "إضافة الطالب"}
</span>
</div>
);
};
export default TabsSubmite;

View File

@ -0,0 +1,76 @@
import * as Yup from "yup";
export const getInitialValues = (objectToEdit: any): any => {
return {
id: objectToEdit?.id ?? null,
// username:objectToEdit?.username ?? null ,
email: objectToEdit?.email ?? "",
username: objectToEdit?.username ?? null,
password: objectToEdit?.password ?? null,
notes: objectToEdit?.notes ?? null,
image: objectToEdit?.image ?? null,
nationality: objectToEdit?.nationality ?? null,
birth_place: objectToEdit?.birth_place ?? null,
birthday: objectToEdit?.birthday ?? null,
phone_number_2: objectToEdit?.phone_number_2 ?? null,
phone_number_1: objectToEdit?.phone_number_1 ?? null,
mother_name: objectToEdit?.mother_name ?? null,
father_name: objectToEdit?.father_name ?? null,
last_name: objectToEdit?.last_name ?? null,
first_name: objectToEdit?.first_name ?? null,
religion: objectToEdit?.religion ?? null,
attachments: objectToEdit?.attachments ?? null,
attachment1: objectToEdit?.attachment1 ?? null,
attachment2: objectToEdit?.attachment2 ?? null,
address: objectToEdit?.address ?? null,
father_job: objectToEdit?.father_job ?? null,
mother_phone_number: objectToEdit?.mother_phone_number ?? null,
father_phone_number: objectToEdit?.father_phone_number ?? null,
mother_job: objectToEdit?.mother_job ?? null,
edu_class_id: objectToEdit?.edu_class_id ?? null,
sex: objectToEdit?.sex ?? null,
};
};
export const getValidationSchema = () => {
return Yup.object().shape({
// username: Yup.string().required('Username is required'),
email: Yup.string().email("validation.Invalid_email"),
username: Yup.string().required("validation.required"),
// .required("validation.Email_is_required"),
password: Yup.string()
.required("validation.Password_is_required")
.min(8, "validation.Password_must_be_at_least_8_characters_long"),
// notes: Yup.string(),
// image: Yup.string().required(),
nationality: Yup.string().required("validation.Nationality_is_required"),
address: Yup.string().required("validation.Address_is_required"),
birth_place: Yup.string().required("validation.Place_of_birth_is_required"),
birthday: Yup.string().required("validation.Date_of_birth_is_required"),
// phone_number_2: Yup.number(),
// phone_number_1: Yup.number(),
mother_name: Yup.string().required("validation.Mother's_name_is_required"),
father_name: Yup.string().required("validation.Father's_name_is_required"),
last_name: Yup.string().required("validation.Last_name_is_required"),
first_name: Yup.string().required("validation.First_name_is_required"),
religion: Yup.string().required("validation.Religion_is_required"),
sex: Yup.string().required("validation.Gender_is_required"),
// attachments: Yup.string(),
// attachment1: Yup.string(),
// attachment2: Yup.string(),
// attachment1: Yup.string().required("validation.Attachment1_is_required"),
father_job: Yup.string().required("validation.Father's_job_is_required"),
// mother_phone_number: Yup.string().required(
// "validation.Mother's_phone_number_is_required",
// ),
father_phone_number: Yup.string().required(
"validation.Father's_phone_number_is_required",
),
// mother_job: Yup.string().required("validation.Mother's_job_is_required"),
});
};

View File

@ -0,0 +1,48 @@
import React, { useState, ReactNode } from "react";
import type { DrawerProps } from "antd";
import { Drawer, Space } from "antd";
interface WithDrawerProps {
button: React.ReactNode;
children: ReactNode;
title: string;
className?: string;
}
const WithDrawer: React.FC<WithDrawerProps> = ({
button,
children,
title = "Basic Drawer",
className,
}) => {
const [open, setOpen] = useState(false);
const [placement, setPlacement] = useState<DrawerProps["placement"]>("right");
return (
<>
<Space>
{React.cloneElement(button as React.ReactElement, {
onClick: () => setOpen(true),
})}
</Space>
<Drawer
title={title}
placement={placement}
closable={false}
onClose={() => setOpen(false)}
open={open}
key={placement}
>
<div className={className}>{children}</div>
</Drawer>
</>
);
};
export default WithDrawer;
// <WithDrawer
// button={<Button type="primary">Open</Button>}
// >
// {/* Your content goes here */}
// </WithDrawer>

View File

@ -0,0 +1,28 @@
import { Form, Formik } from "formik";
import React from "react";
import * as Yup from "yup";
const WithFormik = ({ children }: any) => {
const getInitialValues = () => {
return { name: "" };
};
const getValidationSchema = () => {
return Yup.object().shape({});
};
const handleSubmit = () => {};
return (
<div className="WithFormik">
{
<Formik
onSubmit={handleSubmit}
initialValues={getInitialValues}
validationSchema={getValidationSchema}
>
{(formik) => <Form>{children}</Form>}
</Formik>
}
</div>
);
};
export default WithFormik;

View File

@ -0,0 +1,32 @@
import { useEffect, useRef, useState } from "react";
// This is your Layout Component
const Visibale = ({ children, ...props }: any) => {
const ref = useRef<any>();
const [isVisible, setIsVisible] = useState(false);
useEffect(() => {
const observer = new IntersectionObserver(([entry]) => {
if (isVisible === false) {
setIsVisible(entry.isIntersecting);
}
});
if (ref.current) {
observer.observe(ref.current);
}
return () => {
if (ref.current) {
// eslint-disable-next-line react-hooks/exhaustive-deps
observer.unobserve(ref.current);
}
};
}, [isVisible]); // Empty array ensures effect is only run on mount and unmount
return (
<div ref={ref} {...props}>
{isVisible && children}
</div>
);
};
export default Visibale;

View File

@ -0,0 +1,59 @@
import React from "react";
import Image from "../Ui/Image";
const ActivitySection = () => {
// Static fake data array
const ActivitysData = [
{
id: 1,
image: "/Image/1.png",
info: "3 طالبات حصلوا على جائزة في مسابقة الشطرنج",
time: "منذ 3 ساعات",
},
{
id: 2,
image: "/Image/1.png",
info: "3 طالبات حصلوا على جائزة في مسابقة الشطرنج",
time: "منذ 3 ساعات",
},
{
id: 3,
image: "/Image/1.png",
info: "3 طالبات حصلوا على جائزة في مسابقة الشطرنج",
time: "منذ 3 ساعات",
},
{
id: 4,
image: "/Image/1.png",
info: "3 طالبات حصلوا على جائزة في مسابقة الشطرنج",
time: "منذ 3 ساعات",
},
{
id: 5,
image: "/Image/1.png",
info: "3 طالبات حصلوا على جائزة في مسابقة الشطرنج",
time: "منذ 3 ساعات",
},
];
return (
<div className="ActivitySection">
<header>
<h4>النشاط الطلابي </h4>
</header>
<div className="ActivityScrollerChanger">
<div className="Activitys">
{ActivitysData.map((Activity) => (
<article key={Activity.id}>
<Image src={Activity.image} />
<h5>{Activity.info}</h5>
<p>{Activity?.time}</p>
</article>
))}
</div>
</div>
</div>
);
};
export default ActivitySection;

View File

@ -0,0 +1,123 @@
import React, { useState } from "react";
import dayjs from "dayjs";
import "dayjs/locale/zh-cn";
import type { Dayjs } from "dayjs";
import dayLocaleData from "dayjs/plugin/localeData";
import {
Calendar,
Col,
DatePicker,
Popover,
Radio,
Row,
Select,
Typography,
theme,
} from "antd";
import type { CalendarProps } from "antd";
import { IoMdArrowDropdown } from "react-icons/io";
import { MdOutlineEdit } from "react-icons/md";
import { RiDeleteBin6Fill } from "react-icons/ri";
dayjs.extend(dayLocaleData);
const App: React.FC = () => {
const [year, setYear] = useState<number>(dayjs().year());
const [month, setMonth] = useState<number>(dayjs().month());
const onChangeDatePicker = (value: any) => {
if (value) {
setYear(value.$y); // Extract year from the selected date and update the year state
setMonth(value.$M); // Extract month from the selected date and update the month state
} else {
const today = dayjs(); // Get the current date
setYear(today.year()); // Update the year state to the current year
setMonth(today.month());
}
};
const popoverDays = [
{
day: 10,
month: 3,
year: 2024,
title: "مسابقة الشطرنج الدولية",
time: "الساعة 11",
},
{
day: 22,
month: 3,
year: 2024,
title: "مسابقة الشطرنج الدولية",
time: "الساعة 12",
},
];
const [actionsVisible, setActionsVisible] = useState(0);
const toggleActionsVisibility = (day: number) => {
setActionsVisible(day);
};
const dateCellRender = (value: dayjs.Dayjs) => {
const day = value.date();
const month = value.month() + 1;
const year = value.year();
const matchingDay = popoverDays.find(
(date) => date.day === day && date.month === month && date.year === year,
);
if (matchingDay) {
return (
<Popover
placement="top"
className="CalenderPop"
rootClassName="CalenderPop"
trigger="hover"
content={
<div
className="Calendar_Popover"
onClick={() => toggleActionsVisibility(day)}
>
<h5>{matchingDay.title}</h5>
<h6>{matchingDay.time}</h6>
{actionsVisible === day && ( // Only show actions if actionsVisible is true
<span className="Actions">
<MdOutlineEdit size={22} style={{ color: "#A098AE" }} />
<RiDeleteBin6Fill size={22} style={{ color: "#C11313" }} />
</span>
)}
</div>
}
// open={true}
>
<div className="Calendar_ActiveDiv">{day}</div>
</Popover>
);
}
return <div className="Calendar_Div">{day}</div>;
};
return (
<div className={"CalendarSection"}>
<Calendar
fullscreen={false}
fullCellRender={dateCellRender}
value={dayjs(`${year}-${month + 1}-01`)}
headerRender={() => {
return (
<div className="CalendarHeader">
<h4>تقويم المدرسة</h4>
<DatePicker
suffixIcon={<IoMdArrowDropdown size={30} />}
onChange={(newDate: number) => onChangeDatePicker(newDate)}
picker="month"
/>
</div>
);
}}
/>
</div>
);
};
export default App;

View File

@ -0,0 +1,31 @@
import React from "react";
import { FaMoneyBill } from "react-icons/fa";
import Image from "../Ui/Image";
const CountSection = () => {
const data = [
{ icon: <FaMoneyBill />, name: "الطالبات", number: 900 },
{ icon: <FaMoneyBill />, name: "الطالبات", number: 900 },
{ icon: <FaMoneyBill />, name: "الطالبات", number: 900 },
{ icon: <FaMoneyBill />, name: "الطالبات", number: 900 },
{ icon: <FaMoneyBill />, name: "الطالبات", number: 900 },
];
return (
<div className="CountSection">
<div className="CountCards">
{data?.map((item: any, index: any) => {
return (
<div key={index} className="CountCard">
<i>{item?.icon}</i>
<h4>{item?.name}</h4>
<h6>{item?.number}</h6>
</div>
);
})}
</div>
<Image src="../Home/HomeCounter.png" />
</div>
);
};
export default CountSection;

View File

@ -0,0 +1,82 @@
import React from "react";
import { FaMoneyBill } from "react-icons/fa";
const NoteSection = () => {
// Static fake data array
const notesData = [
{
id: 1,
icon: <FaMoneyBill />,
title: "ملاحظة مالية",
content: [
"الرسوم الدراسية: المبلغ المطلوب من الأهل 200000 ل.س",
"مبلغ أخر: المبلغ المطلوب من الأهل 300000 ل.س",
],
},
{
id: 2,
icon: <FaMoneyBill />,
title: "ملاحظة مالية",
content: [
"الرسوم الدراسية: المبلغ المطلوب من الأهل 200000 ل.س",
"تكلفة أخرى: المبلغ المطلوب من الأهل 150000 ل.س",
"تكلفة أخرى: المبلغ المطلوب من الأهل 150000 ل.س",
"تكلفة أخرى: المبلغ المطلوب من الأهل 150000 ل.س",
],
},
{
id: 3,
icon: <FaMoneyBill />,
title: "ملاحظة مالية",
content: [
"الرسوم الدراسية: المبلغ المطلوب من الأهل 200000 ل.س",
"تكلفة أخرى: المبلغ المطلوب من الأهل 150000 ل.س",
],
},
{
id: 4,
icon: <FaMoneyBill />,
title: "ملاحظة مالية",
content: [
"الرسوم الدراسية: المبلغ المطلوب من الأهل 200000 ل.س",
"تكلفة أخرى: المبلغ المطلوب من الأهل 150000 ل.س",
"تكلفة أخرى: المبلغ المطلوب من الأهل 150000 ل.س",
"تكلفة أخرى: المبلغ المطلوب من الأهل 150000 ل.س",
],
},
{
id: 5,
icon: <FaMoneyBill />,
title: "ملاحظة مالية",
content: [
"الرسوم الدراسية: المبلغ المطلوب من الأهل 200000 ل.س",
"تكلفة أخرى: المبلغ المطلوب من الأهل 150000 ل.س",
],
},
];
return (
<div className="NoteSection">
<header>
<h4>ملاحظات اليوم</h4> <h6>8/3/2021</h6>
</header>
<div className="NoteScrollerChanger">
<div className="Notes">
{notesData.map((note) => (
<article key={note.id}>
<div>
<i>{note.icon}</i>
<h5>{note.title}</h5>
</div>
{note.content.map((item, index) => (
<span key={index}>{item}</span>
))}
</article>
))}
</div>
</div>
</div>
);
};
export default NoteSection;

View File

@ -0,0 +1,72 @@
import { Progress, Select } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { FaLaptop } from "react-icons/fa";
import { IoMdArrowDropdown } from "react-icons/io";
import Image from "../Ui/Image";
const StudentSubjects = () => {
const [selectedOption, setSelectedOption] = useState("هذا الأسبوع");
const Options = [
{ value: "هذا الأسبوع", label: "هذا الأسبوع" },
{ value: "الأسبوع الماضي", label: "الأسبوع الماضي" },
{ value: "الشهر الماضي", label: "الشهر الماضي" },
];
const handleChangeSelect = (value: any) => {
setSelectedOption(value);
// console.log(`Selected ${value}`);
};
const [t] = useTranslation();
// Define static data
const staticData = [
{
SubjectImage: "/Subject/algebra.png",
SubjectName: "طالبات",
StudentSubjectsPercent: 50,
},
{
SubjectImage: "/Subject/flask.png",
SubjectName: "طالبات",
StudentSubjectsPercent: 60,
},
{
SubjectImage: "/Subject/koran.png",
SubjectName: "طالبات",
StudentSubjectsPercent: 70,
},
];
return (
<div className="StudentSubjects">
<header>
<h6>{t("عدد الطالبات")}</h6>
<Select
defaultValue={selectedOption}
onChange={handleChangeSelect}
suffixIcon={<IoMdArrowDropdown size={30} />}
options={Options}
/>
</header>
<main>
{staticData.map((item, index) => (
<div key={index}>
<Progress
type="circle"
size={"small"}
strokeColor={"#0052B4"}
strokeWidth={7}
percent={item?.StudentSubjectsPercent}
/>
<h6>{item.SubjectName}</h6>
<Image src={item?.SubjectImage} />
</div>
))}
</main>
</div>
);
};
export default StudentSubjects;

View File

@ -1,11 +1,11 @@
import { Spin } from "antd"; import { Spin } from 'antd'
const SpinContainer = () => { const SpinContainer = () => {
return ( return (
<div className="SpinContainer"> <div className='SpinContainer'>
<Spin /> <Spin/>
</div> </div>
); )
}; }
export default SpinContainer; export default SpinContainer

View File

@ -0,0 +1,46 @@
import { Col, Row } from "reactstrap";
import React from "react";
import ValidationField from "../../../../Components/ValidationField/ValidationField";
const Form = () => {
return (
<Row>
<Col xs="8" sm="8">
{" "}
{/* This column will take up 8 units on extra small screens and 6 units on small screens */}
<ValidationField name="الجنس" />
<ValidationField name="الاسم الأول *" />
<ValidationField name="اسم العائلة" />
<div className="TowValidationItems">
<ValidationField name="اسم العائلة" />
<ValidationField name="اسم العائلة" no_label />
</div>
<div className="TowValidationItems">
<ValidationField name="اسم العائلة" type="Select" option={[]} />
<ValidationField name="اسم العائلة" />
</div>
{/* <div className='TowValidationItems'>
<ValidationField name='اسم العائلة'/>
<ValidationField name='اسم العائلة' no_label/>
</div>
<div className='TowValidationItems'>
<ValidationField name='اسم العائلة'/>
<ValidationField name='اسم العائلة' no_label/>
</div> */}
</Col>
<Col xs="4" sm="4">
{" "}
{/* This column will take up 4 units on extra small screens and 6 units on small screens */}
<ValidationField name="DropFile" type="DropFile" label="الصورة *" />
<ValidationField
name="DropFile"
type="DropFile"
label="الوثيقة المدرسية *"
/>
</Col>
</Row>
);
};
export default Form;

View File

@ -0,0 +1,38 @@
import React, { useState } from "react";
import { Modal } from "antd";
import { useModalState } from "../../../../zustand/Modal";
import FormikForm from "../../../../Layout/Dashboard/FormikForm";
import * as Yup from "yup";
import ModelBody from "./ModelBody";
import TabsSubmite from "../../../../Components/Layout/Tabs/TabsSubmite";
import { getInitialValues, getValidationSchema } from "./formUtil";
import { ModalEnum } from "../../../../enums/Model";
const ModalForm: React.FC = () => {
const { isOpen, setIsOpen } = useModalState((state) => state);
return (
<>
<Modal
className="AddModalForm"
centered
width={"80vw"}
footer={null}
open={isOpen === ModalEnum.STUDENT_ADD}
onOk={() => setIsOpen("")}
onCancel={() => setIsOpen("")}
>
<FormikForm
handleSubmit={() => {}}
initialValues={getInitialValues}
validationSchema={getValidationSchema}
>
<ModelBody />
{/* <TabsSubmite steps={5} /> */}
</FormikForm>
</Modal>
</>
);
};
export default ModalForm;

View File

@ -0,0 +1,60 @@
import { Divider, Steps } from "antd";
import React, { useState } from "react";
import { useTabsState } from "../../../../zustand/TabsState";
import { useModalTabsState } from "../../../../zustand/ModalTabsState";
import Form from "./Form";
import TabsBar from "../../../../Components/Layout/Tabs/TabsBar";
import ActiveTabs from "../../../../Components/Layout/Tabs/ActiveTabs";
const ModelBody = () => {
const { ActiveTab, setActiveTab } = useModalTabsState((state) => state);
function handelTabClick(index: number) {
setActiveTab(index);
}
const steps = [
{
title: "الخطوة 1",
description: "التفاصيل الشخصية",
component: <Form />,
},
{
title: "الخطوة 2",
description: "التفاصيل الشخصية",
component: <>H2</>,
},
{
title: "الخطوة 3",
description: "التفاصيل الشخصية",
component: <>H2</>,
},
{
title: "الخطوة 4",
description: "التفاصيل الشخصية",
component: <>H2</>,
},
{
title: "الخطوة 5",
description: "التفاصيل الشخصية",
component: <>H2</>,
},
{
title: "الخطوة 5",
description: "التفاصيل الشخصية",
component: <>H2</>,
hidden: true,
},
];
return (
<div className="ModelBody">
<TabsBar steps={steps} />
<div className="ModelBodyForm">
<header>إضافة طالب</header>
<ActiveTabs steps={steps} />
</div>
</div>
);
};
export default ModelBody;

View File

@ -0,0 +1,15 @@
import * as Yup from "yup";
export const getInitialValues = (objectToEdit: any): any => {
return {
id: objectToEdit?.id ?? 0,
name: objectToEdit?.name ?? "",
};
};
export const getValidationSchema = () => {
// validate input
return Yup.object().shape({
name: Yup.string().required("مطلوب"),
});
};

View File

@ -0,0 +1,26 @@
import React from "react";
import { FaMoneyBill } from "react-icons/fa";
import Image from "../Ui/Image";
const CountSection = () => {
return (
<div className="CountSection">
<div className="CountCards">
{[1, 2, 3, 4, 5]?.map((item: any, index: any) => {
return (
<div key={index} className="CountCard">
<i>
<FaMoneyBill />
</i>
<h4>الطالبات</h4>
<h6>932</h6>
</div>
);
})}
</div>
{/* <Image src='../Home/HomeCounter.png'/> */}
</div>
);
};
export default CountSection;

View File

@ -0,0 +1,21 @@
import React from "react";
import { FaChalkboardTeacher } from "react-icons/fa";
import { IoSchool } from "react-icons/io5";
import { useNavigate } from "react-router-dom";
const DetailsCard = () => {
const navigate = useNavigate();
const handelclick = () => {
navigate("/student/add");
};
return (
<div className="DetailsCard" onClick={() => handelclick()}>
<h6>إضافة طالب</h6>
<div>
<IoSchool />
</div>
</div>
);
};
export default DetailsCard;

View File

@ -0,0 +1,56 @@
import { Select } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { FaLaptop } from "react-icons/fa";
import { IoMdArrowDropdown } from "react-icons/io";
const StudentCount = () => {
const [selectedOption, setSelectedOption] = useState("هذا الأسبوع");
const Options = [
{ value: "هذا الأسبوع", label: "هذا الأسبوع" },
{ value: "الأسبوع الماضي", label: "الأسبوع الماضي" },
{ value: "الشهر الماضي", label: "الشهر الماضي" },
];
const handleChangeSelect = (value: any) => {
setSelectedOption(value);
// console.log(`Selected ${value}`);
};
const [t] = useTranslation();
// Define static data
const staticData = [
{ studentName: "طالبات الشعبة الأولى 1", studentCount: 50 },
{ studentName: "طالبات الشعبة الأولى 2", studentCount: 60 },
{ studentName: "طالبات الشعبة الأولى 3", studentCount: 70 },
{ studentName: "طالبات الشعبة الأولى 4", studentCount: 80 },
];
return (
<div className="StudentCount">
<header>
<h6>{t("عدد الطالبات")}</h6>
<Select
defaultValue={selectedOption}
onChange={handleChangeSelect}
suffixIcon={<IoMdArrowDropdown size={30} />}
options={Options}
/>
</header>
<main>
{staticData.map((item, index) => (
<div key={index}>
<span>
<h6>{item.studentName}</h6>
<p>{item.studentCount} طالب</p>
</span>
<FaLaptop />
</div>
))}
</main>
</div>
);
};
export default StudentCount;

View File

@ -0,0 +1,54 @@
import React from "react";
import { FaMoneyBill } from "react-icons/fa";
import Image from "../../Ui/Image";
import { useNavigate, useParams } from "react-router-dom";
import { useGetOverView } from "../../../api/payment";
import { useTranslation } from "react-i18next";
import { Currency } from "../../../config/AppKey";
import { formatNumber } from "../../../utils/formatNumber";
const MoneyState = () => {
const navigation = useNavigate();
const { student_id } = useParams();
const handelnavigate = () => {
navigation(`payment`);
};
const { data } = useGetOverView({
student_id: student_id,
});
const [t] = useTranslation();
const to_be_paid = Number(data?.data?.to_be_paid) || 0;
const paid = Number(data?.data?.paid) || 0;
const dues = formatNumber(to_be_paid - paid);
return (
<div className="MoneyState">
<header>{t("header.The_student_financial_situation")}</header>
<main>
<button>
{t("select.Payments.dues")} : {dues} {Currency}
</button>
<div>
<div>
<FaMoneyBill />
</div>
<span>
<h6>{t("select.Payments.to_be_paid")}</h6>
<p>
{formatNumber(to_be_paid)} {Currency}
</p>
</span>
</div>
<article>
<span onClick={handelnavigate}>
<Image src="/Icon/cash.png" />
<h5>{t("models.payment")}</h5>
<button>{t("practical.details")}</button>
</span>
</article>
</main>
</div>
);
};
export default MoneyState;

View File

@ -0,0 +1,35 @@
import React, { useState } from "react";
function FakeIntegration() {
const [integrationInput, setIntegrationInput] = useState("");
const [integrationResult, setIntegrationResult] = useState("");
const handleSubmit = (event: any) => {
event.preventDefault();
// Simulated integration result
const fakeResult = "∫(x^2)dx = (1/3)x^3 + C";
setIntegrationResult(fakeResult);
};
return (
<div>
<form onSubmit={handleSubmit}>
<input
type="text"
value={integrationInput}
onChange={(e) => setIntegrationInput(e.target.value)}
placeholder="Enter integration expression"
/>
<button type="submit">Calculate</button>
</form>
<div>
<h2>Integration Input:</h2>
<p>{integrationInput}</p>
<h2>Integration Result:</h2>
<p>{integrationResult}</p>
</div>
</div>
);
}
export default FakeIntegration;

View File

@ -1,39 +1,40 @@
import { DatePicker } from "antd"; import { DatePicker } from 'antd'
import React from "react"; import React from 'react'
import { useTranslation } from "react-i18next"; import { useTranslation } from 'react-i18next';
import { useObjectToEdit } from "../../../zustand/ObjectToEditState"; import { useObjectToEdit } from '../../../zustand/ObjectToEditState';
import { useLocation, useNavigate } from "react-router-dom"; import { useLocation, useNavigate } from 'react-router-dom';
import type { DatePickerProps } from "antd"; import type { DatePickerProps } from "antd";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { DateEnum } from "../../../enums/Date"; import { DateEnum } from '../../../enums/Date';
const CustomDatePicker = () => { const CustomDatePicker = () => {
const [t] = useTranslation(); const [t] = useTranslation();
const { setParamToSend, paramToSend } = useObjectToEdit(); const { setParamToSend, paramToSend } = useObjectToEdit();
const navigate = useNavigate(); const navigate = useNavigate();
const location = useLocation(); const location = useLocation();
const onChange: DatePickerProps["onChange"] = (date, dateString) => {
// console.log(date, dateString);
const newObj = { ...paramToSend };
newObj.date = dateString;
setParamToSend(newObj);
navigate(
`${location.pathname}?${paramToSend?.state ?? "all"}=${dateString}`,
);
};
const Today = new Date() as any;
const onChange: DatePickerProps["onChange"] = (date, dateString) => {
// console.log(date, dateString);
const newObj = { ...paramToSend };
newObj.date = dateString;
setParamToSend(newObj);
navigate(
`${location.pathname}?${paramToSend?.state ?? "all"}=${dateString}`,
);
};
const Today = new Date() as any;
return ( return (
<div className="CustomDatePicker"> <div className="CustomDatePicker">
<DatePicker <DatePicker
defaultValue={dayjs(Today)} defaultValue={dayjs(Today)}
placeholder={t(`input.select_date`)} placeholder={t(`input.select_date`)}
onChange={onChange} onChange={onChange}
format={DateEnum?.FORMATE} format={DateEnum?.FORMATE}
/> />
</div> </div>
); )
}; }
export default CustomDatePicker; export default CustomDatePicker

View File

@ -0,0 +1,56 @@
import React, { memo } from "react";
import type { MenuProps } from "antd";
import { Button, Dropdown, Space } from "antd";
import { useTranslation } from "react-i18next";
import { BsFillMoonStarsFill, BsFillSunFill } from "react-icons/bs";
import { useChangeTheme } from "../../Hooks/useChangeTheme";
const Theme: React.FC = () => {
const { currentTheme, changeTheme } = useChangeTheme();
const { t } = useTranslation();
const LightTheme = memo(() => (
<div className="MenuChange" onClick={lightThemeClickHandler}>
<BsFillSunFill />
{t("light")}
</div>
));
const DarkTheme = memo(() => (
<div className="MenuChange" onClick={darkThemeClickHandler}>
<BsFillMoonStarsFill />
{t("dark")}
</div>
));
const lightThemeClickHandler = React.useCallback(() => {
changeTheme("light");
}, [changeTheme]);
const darkThemeClickHandler = React.useCallback(() => {
changeTheme("dark");
}, [changeTheme]);
const items: MenuProps["items"] = [
{
key: "1",
label: <LightTheme />,
},
{
key: "2",
label: <DarkTheme />,
},
];
return (
<Space direction="vertical">
<Dropdown menu={{ items }} placement="top">
<Button>
{currentTheme === "dark" ? <DarkTheme /> : <LightTheme />}
</Button>
</Dropdown>
</Space>
);
};
export default Theme;

View File

@ -31,11 +31,11 @@ const components: { [key: string]: React.FC<any> } = {
MaltyFile: MaltyFile, MaltyFile: MaltyFile,
Checkbox: CheckboxField, Checkbox: CheckboxField,
NumberFormate: NumberFormate, NumberFormate: NumberFormate,
Number: NumberField, Number:NumberField
}; };
const ValidationField: React.FC<ValidationFieldProps> = React.memo( const ValidationField: React.FC<ValidationFieldProps> = React.memo(
({ type, ...otherProps }: any) => { ({ type, ...otherProps }:any) => {
const Component = components[type as ValidationFieldType]; const Component = components[type as ValidationFieldType];
if (!Component) { if (!Component) {

View File

@ -1,7 +1,7 @@
import React from "react"; import React from "react";
import useFormField from "../../../Hooks/useFormField"; import useFormField from "../../../Hooks/useFormField";
import { Checkbox, Form } from "antd"; import { Checkbox, Form } from "antd";
import { getNestedValue } from "../utils/getNestedValue"; import {getNestedValue} from '../utils/getNestedValue'
const CheckboxField = ({ const CheckboxField = ({
name, name,
label, label,

View File

@ -25,7 +25,9 @@ const Default = ({
<label htmlFor={name} className="text"> <label htmlFor={name} className="text">
{label2} {label2}
</label> </label>
) : no_label ? ( )
:no_label ? (
<label htmlFor={name} className="text"> <label htmlFor={name} className="text">
<span>empty</span> <span>empty</span>
</label> </label>
@ -56,6 +58,7 @@ const Default = ({
name={name} name={name}
disabled={isDisabled} disabled={isDisabled}
size="large" size="large"
{...(type === "number" && { min: 0 })} {...(type === "number" && { min: 0 })}
{...props} {...props}
/> />

View File

@ -12,27 +12,27 @@ const File = ({
className, className,
props, props,
}: any) => { }: any) => {
const { formik, t, isError, errorMsg } = useFormField(name, props); const { formik, t, isError,errorMsg } = useFormField(name, props);
let imageUrl = formik?.values?.[name] ?? null; let imageUrl = formik?.values?.[name] ?? null;
console.log(imageUrl); console.log(imageUrl);
console.log(typeof imageUrl === "string"); console.log(typeof imageUrl === 'string');
const fileList: UploadFile[] = useMemo(() => { const fileList: UploadFile[] = useMemo(() => {
if (!imageUrl) return []; if (!imageUrl) return [];
return [ return [
typeof imageUrl === "string" typeof imageUrl === 'string'
? { ? {
uid: "-1", uid: '-1',
name: "uploaded-image", name: 'uploaded-image',
status: "done", status: 'done',
url: imageUrl, url: imageUrl,
thumbUrl: imageUrl, thumbUrl: imageUrl,
} }
: { : {
uid: imageUrl.uid || "-1", uid: imageUrl.uid || '-1',
name: imageUrl.name || "uploaded-image", name: imageUrl.name || 'uploaded-image',
status: "done", status: 'done',
originFileObj: imageUrl, originFileObj: imageUrl,
}, },
]; ];
@ -70,6 +70,7 @@ const File = ({
icon={<UploadOutlined />} icon={<UploadOutlined />}
> >
{placholder ?? t("input.Click_to_upload_the_image")} {placholder ?? t("input.Click_to_upload_the_image")}
</Button> </Button>
<div className="Error_color"> {isError ? "required" : ""}</div> <div className="Error_color"> {isError ? "required" : ""}</div>
{errorMsg} {errorMsg}

View File

@ -16,12 +16,12 @@ const NumberField = ({
label_icon, label_icon,
...props ...props
}: ValidationFieldPropsInput) => { }: ValidationFieldPropsInput) => {
const { errorMsg, isError, t, formik } = useFormField(name, props); const { errorMsg, isError, t ,formik} = useFormField(name, props);
const handleChange = ( const handleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>, e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
) => { ) => {
console.log("Change:", e); console.log('Change:', e);
formik.setFieldValue(name, e); formik.setFieldValue(name, e);
}; };

View File

@ -64,6 +64,7 @@ const NumberFormate = ({
disabled={isDisabled} disabled={isDisabled}
size="large" size="large"
// onChange={onChange ? onChange : handleChange} // onChange={onChange ? onChange : handleChange}
/> />
</Form.Item> </Form.Item>

View File

@ -17,7 +17,7 @@ const SearchField = ({
props, props,
no_label, no_label,
label_icon, label_icon,
isLoading, isLoading
}: any) => { }: any) => {
const { errorMsg, isError, t, formik } = useFormField(name, props); const { errorMsg, isError, t, formik } = useFormField(name, props);
const [searchQuery, setSearchQuery] = useState<string>(""); const [searchQuery, setSearchQuery] = useState<string>("");
@ -78,7 +78,8 @@ const SearchField = ({
onChange={onChange || SelectableChange} onChange={onChange || SelectableChange}
showSearch showSearch
optionFilterProp="label" optionFilterProp="label"
notFoundContent={isLoading ? <Spin /> : "لا يوجد"} notFoundContent={isLoading ? <Spin/> : "لا يوجد" }
onSearch={SearchHandleChange} onSearch={SearchHandleChange}
/> />
</Form.Item> </Form.Item>

View File

@ -15,7 +15,7 @@ const TextField = ({
props, props,
no_label, no_label,
label_icon, label_icon,
className, className
}: any) => { }: any) => {
const { formik, isError, errorMsg, t } = useFormField(name, props); const { formik, isError, errorMsg, t } = useFormField(name, props);
const TextFilehandleChange = ( const TextFilehandleChange = (
@ -33,14 +33,14 @@ const TextField = ({
) : label_icon ? ( ) : label_icon ? (
<div className="LabelWithIcon"> <div className="LabelWithIcon">
<label htmlFor={name} className="text"> <label htmlFor={name} className="text">
{label2 ? label2 : t(`input.${label ? label : name}`)} {label2 ? label2 : t(`input.${label ? label : name}`) }
</label> </label>
<MdOutlineEdit size={22} style={{ color: "#A098AE" }} /> <MdOutlineEdit size={22} style={{ color: "#A098AE" }} />
</div> </div>
) : ( ) : (
<label htmlFor={name} className="text"> <label htmlFor={name} className="text">
{label2 ? label2 : t(`input.${label ? label : name}`)} {label2 ? label2 : t(`input.${label ? label : name}`) }
</label> </label>
)} )}
<Form.Item <Form.Item
@ -57,7 +57,9 @@ const TextField = ({
showCount showCount
maxLength={1000} maxLength={1000}
onChange={onChange || TextFilehandleChange} onChange={onChange || TextFilehandleChange}
style={{ height: 120 }} style={{height:120}}
/> />
</Form.Item> </Form.Item>
</div> </div>

View File

@ -62,8 +62,9 @@
} }
.Checkboxs { .Checkboxs {
padding: 4%; padding: 4%;
} }
.ant-checkbox-wrapper { .ant-checkbox-wrapper{
min-width: 100px; min-width: 100px;
} }
.SearchField { .SearchField {
@ -202,26 +203,27 @@ input:-webkit-autofill:hover {
margin-bottom: 20px; margin-bottom: 20px;
} }
.ant-checkbox-wrapper {
.ant-checkbox-wrapper{
margin-top: 25px !important; margin-top: 25px !important;
} }
.add_new_button { .add_new_button{
margin-bottom: 20px; margin-bottom: 20px;
svg { svg{
color: var(--primary); color: var(--primary);
} }
} }
.ValidationField:has(.input_number) { .ValidationField:has(.input_number){
max-width: 100px; max-width: 100px;
.input_number { .input_number{
max-width: 100px; max-width: 100px;
} }
} }
.flex { .flex{
display: flex; display: flex;
gap: 30px; gap: 30px ;
max-width: 80% !important; max-width: 80% !important;
} }

View File

@ -1,7 +1,9 @@
export function getNestedValue(obj: any, path: any) {
export function getNestedValue(obj:any, path:any) {
return path return path
.replace(/\?.\[|\]\[|\]\.?/g, ".") // Replace question mark and square brackets .replace(/\?.\[|\]\[|\]\.?/g, '.') // Replace question mark and square brackets
.split(".") // Split by dots .split('.') // Split by dots
.filter(Boolean) // Remove empty strings .filter(Boolean) // Remove empty strings
.reduce((acc: any, key: any) => acc && acc[key], obj); // Access nested properties .reduce((acc:any, key:any) => acc && acc[key], obj); // Access nested properties
} }

View File

@ -73,7 +73,7 @@ export interface ValidationFieldPropsSearch {
option: any[]; option: any[];
isMulti?: boolean; isMulti?: boolean;
searchBy: string; searchBy: string;
isLoading?: any; isLoading?:any
} }
export interface ValidationFieldPropsDataRange { export interface ValidationFieldPropsDataRange {
name: string; name: string;
@ -151,7 +151,7 @@ export interface ValidationFieldPropstext {
| "TextArea" | "TextArea"
| "NumberFormate"; | "NumberFormate";
label?: string; label?: string;
label2?: string; label2?:string;
className?: string; className?: string;
placeholder?: string; placeholder?: string;
isDisabled?: boolean; isDisabled?: boolean;
@ -161,26 +161,31 @@ export interface ValidationFieldPropstext {
[key: string]: any; // Index signature to allow any additional props [key: string]: any; // Index signature to allow any additional props
} }
///// new ///// new
export interface BaseField { export interface BaseField {
name: string; name: string;
label?: string; label?: string;
placeholder?: string; placeholder?: string;
} }
export type OmitBaseType = "placeholder" | "name" | "label" | "type"; export type OmitBaseType = 'placeholder' | 'name' | 'label' | 'type';
export type OmitPicker = OmitBaseType | "format"; export type OmitPicker = OmitBaseType | 'format';
export interface ValidationFieldPropsInput export interface ValidationFieldPropsInput
extends Omit<InputProps, OmitBaseType>, extends Omit<InputProps, OmitBaseType>,
BaseField { BaseField {
type: "text" | "number" | "password" | "email" | "Number"; type: 'text' | 'number' | 'password' | 'email' | "Number";
isDisabled?: boolean; isDisabled?:boolean
no_label?: string; no_label?:string
label_icon?: string; label_icon?:string
label2?: string; label2?:string
} }
export type ValidationFieldProps = export type ValidationFieldProps =
| ValidationFieldPropsInput | ValidationFieldPropsInput
| ValidationFieldPropsSelect | ValidationFieldPropsSelect

View File

@ -0,0 +1,60 @@
import Image from "../Ui/Image";
import { Student } from "../../types/Item";
import { useNavigate, useParams } from "react-router-dom";
import { useGetStudent } from "../../api/student";
import { useTranslation } from "react-i18next";
const StudentBehavior = () => {
const { student_id } = useParams();
const { data: studentData } = useGetStudent({
show: student_id,
});
const userData: Student | {} = studentData?.data ?? {};
const { positiveNote, warningNote, alertNote } = userData as Student;
const [t] = useTranslation();
const navigate = useNavigate();
const handelnavigate = () => {
navigate(`note`);
};
const Data = [
{
icon: "/Icon/medal.png",
title: t("array.UserInfo.appreciation"),
value: positiveNote,
buttonText: t("practical.show"),
},
{
icon: "/Icon/warning.png",
title: t("array.UserInfo.warning"),
value: warningNote,
buttonText: t("practical.show"),
},
{
icon: "/Icon/Error.png",
title: t("array.UserInfo.alert"),
value: alertNote,
buttonText: t("practical.show"),
},
];
return (
<div className="StudentBehavior">
<header>{t("header.Student_classroom_behavior")}</header>
<main>
{Data.map((item, index) => (
<article key={index} onClick={handelnavigate}>
<Image src={item.icon} />
<div>
<h6>{item.title}</h6>
<p>{item.value}</p>
</div>
<button>{item.buttonText}</button>
</article>
))}
</main>
</div>
);
};
export default StudentBehavior;

View File

@ -0,0 +1,97 @@
import React from "react";
import { getColorName } from "../../Hooks/usePercentage";
import { useNavigate, useParams } from "react-router-dom";
import { useGetStudent } from "../../api/student";
import { Student } from "../../types/Item";
import { useTranslation } from "react-i18next";
interface StudentTimeData {
id: number;
absences: number;
justified: number;
unjustified: number;
totalDays: number;
name: string;
}
const StudentsTime = () => {
const { student_id } = useParams();
const { data: studentData } = useGetStudent({
show: student_id,
});
const userData: Student | {} = studentData?.data ?? {};
const { ealryDeparture, absence, lateArrival } = userData as Student;
const [t] = useTranslation();
const data = [
{
name: t("models.absence"),
id: 1,
absences: absence?.justified + absence?.not_justified,
justified: absence?.justified,
unjustified: absence?.not_justified,
totalDays: absence?.total,
},
{
name: t("models.late_arrival"),
id: 2,
absences: lateArrival?.justified + lateArrival?.not_justified,
justified: lateArrival?.justified,
unjustified: lateArrival?.not_justified,
totalDays: lateArrival?.total,
},
{
name: t("models.earlyDeparture"),
id: 3,
absences: ealryDeparture?.justified + ealryDeparture?.not_justified,
justified: ealryDeparture?.justified,
unjustified: ealryDeparture?.not_justified,
totalDays: ealryDeparture?.total,
},
];
const navigate = useNavigate();
const handel_naviagate = () => {
navigate(`status`);
};
return (
<div className="StudentsTime">
<header>{t("header.student_status")}</header>
<main>
{data?.length > 0 &&
data.map((item: StudentTimeData, index: number) => {
return (
<article key={item.id} onClick={handel_naviagate}>
<span>
<h6>{item?.name}</h6>
<p data-color={getColorName(item.absences)}>
{item.absences}
</p>
</span>
<div>
<span>
<div>
{t("select.Student_Type.justified")}
<span>{item.justified}</span>
</div>
<div>
{t("select.Student_Type.not_justified")}
<span>{item.unjustified}</span>
</div>
</span>
<span>
<div className="StudentsTimeTotal">المجموع</div>
<p>
{item.absences} من {item.totalDays} يوم
</p>
</span>
</div>
</article>
);
})}
</main>
</div>
);
};
export default StudentsTime;

View File

@ -1,26 +1,28 @@
import { useFormikContext } from "formik"; import { useFormikContext } from 'formik';
import React from "react"; import React 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 { QUESTION_OBJECT_KEY } from '../../config/AppKey';
const Header = () => { const Header = () => {
const [t] = useTranslation(); const [t] = useTranslation();
const { values, setFieldValue, setValues } = useFormikContext<any>(); const { values, setFieldValue,setValues } = useFormikContext<any>();
const { isBseQuestion, setIsBseQuestion } = useObjectToEdit(); const {isBseQuestion,setIsBseQuestion} = useObjectToEdit()
const { setSavedQuestionData } = useObjectToEdit(); const {setSavedQuestionData} = useObjectToEdit()
const handleChange = () => { const handleChange = () => {
setSavedQuestionData(null); setSavedQuestionData(null)
localStorage.removeItem(QUESTION_OBJECT_KEY); localStorage.removeItem(QUESTION_OBJECT_KEY)
if (isBseQuestion) { if (isBseQuestion) {
setIsBseQuestion(false); setIsBseQuestion(false)
setValues(null); setValues(null)
setFieldValue("isBase", 0); setFieldValue("isBase",0)
} else { } else {
setIsBseQuestion(true);
setValues(null); setIsBseQuestion(true)
setFieldValue("isBase", 1); setValues(null)
setFieldValue("isBase",1)
} }
}; };
@ -31,9 +33,7 @@ const Header = () => {
</div> </div>
<div> <div>
<GoArrowSwitch onClick={handleChange} className="m-2" /> <GoArrowSwitch onClick={handleChange} className="m-2" />
{isBseQuestion || values?.isBase === 1 {isBseQuestion || values?.isBase === 1 ? t("header.malty_exercise") :t("header.exercise") }
? t("header.malty_exercise")
: t("header.exercise")}
</div> </div>
</header> </header>
); );

View File

@ -0,0 +1,62 @@
import React, { useState, useEffect, useRef } from 'react';
import katex from 'katex';
import 'katex/dist/katex.min.css';
const MathInput: React.FC = () => {
const [latex, setLatex] = useState<string>('f(x) = \\frac{1}{1+e^{-x}}');
const displayRef = useRef<HTMLDivElement>(null);
useEffect(() => {
renderLatex();
}, [latex]);
//// tow input show and edit
const renderLatex = () => {
if (displayRef.current) {
try {
katex.render(latex, displayRef.current, {
throwOnError: false,
displayMode: true,
});
} catch (error) {
console.error('KaTeX rendering error:', error);
displayRef.current.textContent = 'Error rendering LaTeX';
}
}
};
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setLatex(event.target.value);
};
return (
<div style={{ padding: '20px' }}>
<input
type="text"
value={latex}
onChange={handleInputChange}
style={{
width: '100%',
padding: '10px',
fontSize: '16px',
border: '1px solid #ccc',
borderRadius: '4px',
fontFamily: 'monospace',
marginBottom: '10px',
}}
/>
<div
ref={displayRef}
style={{
width: '100%',
padding: '10px',
fontSize: '16px',
border: '1px solid #ccc',
borderRadius: '4px',
minHeight: '40px',
}}
/>
</div>
);
};
export default MathInput;

View File

@ -0,0 +1,68 @@
import React, { useState, useEffect, useRef } from 'react';
import katex from 'katex';
import 'katex/dist/katex.min.css';
const MathInput: React.FC = () => {
const [latex, setLatex] = useState<string>('f(x) = \\frac{1}{1+e^{-x}}');
const inputRef = useRef<HTMLDivElement>(null);
const [isEditing, setIsEditing] = useState<boolean>(false);
useEffect(() => {
renderLatex();
}, [latex, isEditing]);
const renderLatex = () => {
if (inputRef.current && !isEditing) {
try {
katex.render(latex, inputRef.current, {
throwOnError: false,
displayMode: true,
});
} catch (error) {
console.error('KaTeX rendering error:', error);
inputRef.current.textContent = 'Error rendering LaTeX';
}
}
};
const handleInput = () => {
if (inputRef.current) {
setLatex(inputRef.current.textContent || '');
}
};
const handleFocus = () => {
setIsEditing(true);
if (inputRef.current) {
inputRef.current.textContent = latex;
}
};
const handleBlur = () => {
setIsEditing(false);
};
return (
<div style={{ padding: '20px' }}>
<div
ref={inputRef}
contentEditable
onInput={handleInput}
onFocus={handleFocus}
onBlur={handleBlur}
style={{
width: '100%',
padding: '10px',
fontSize: '16px',
border: '1px solid #ccc',
borderRadius: '4px',
minHeight: '40px',
fontFamily: isEditing ? 'monospace' : 'inherit',
cursor: 'text',
}}
/>
</div>
);
};
export default MathInput;

View File

@ -1,3 +1,4 @@
export const useAddKeyToData = (dataSource: any, identifier = "id") => { export const useAddKeyToData = (dataSource: any, identifier = "id") => {
if (!dataSource || !Array.isArray(dataSource)) { if (!dataSource || !Array.isArray(dataSource)) {
return []; return [];

View File

@ -0,0 +1,23 @@
import { useCallback, useEffect, useState } from "react";
export const useChangeTheme = () => {
const [currentTheme, setCurrentTheme] = useState(
localStorage.getItem("theme") ?? "light",
);
useEffect(() => {
if (currentTheme === "dark") {
document.body.classList.add("dark");
} else {
document.body.classList.remove("dark");
}
localStorage.setItem("theme", currentTheme);
}, [currentTheme]);
const changeTheme = useCallback((newTheme: any) => {
setCurrentTheme(newTheme);
}, []);
return { currentTheme, changeTheme };
};

View File

@ -0,0 +1,18 @@
import { useState } from "react";
const useDifferenceData = (values: any, data: any) => {
const [newData, setNewData] = useState({});
for (const key in data) {
if (values[key] !== data[key]) {
setNewData((prevData) => ({
...prevData,
[key]: values[key],
}));
}
}
return newData;
};
export default useDifferenceData;

View File

@ -0,0 +1,40 @@
import { useEffect } from "react";
const useDisableShortcutsAndRightClick = () => {
useEffect(() => {
const disableShortcutsAndRightClick = (event: Event) => {
// Check for Ctrl+Shift+C or F12
if (
(event as KeyboardEvent).ctrlKey &&
(event as KeyboardEvent).shiftKey &&
((event as KeyboardEvent).key === "C" ||
(event as KeyboardEvent).key === "c" ||
(event as KeyboardEvent).keyCode === 123) /* F12 key code */
) {
event.preventDefault();
}
};
const disableRightClick = (event: MouseEvent) => {
event.preventDefault();
};
document.addEventListener("keydown", disableShortcutsAndRightClick);
document.addEventListener("contextmenu", disableRightClick);
// Attempt to prevent F12 key default behavior
document.addEventListener("keydown", (event) => {
if (event.key === "F12" || event.keyCode === 123) {
event.preventDefault();
return false;
}
});
return () => {
document.removeEventListener("keydown", disableShortcutsAndRightClick);
document.removeEventListener("contextmenu", disableRightClick);
};
}, []);
};
export default useDisableShortcutsAndRightClick;

View File

@ -1,12 +1,8 @@
import { useEffect } from "react"; import { useEffect } from 'react';
type ModifierKey = "ctrlKey" | "shiftKey" | "altKey" | "metaKey"; type ModifierKey = 'ctrlKey' | 'shiftKey' | 'altKey' | 'metaKey';
const useKeyPress = ( const useKeyPress = (targetKey: string, modifierKey: ModifierKey, callback:any) => {
targetKey: string,
modifierKey: ModifierKey,
callback: any,
) => {
useEffect(() => { useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => { const handleKeyDown = (event: KeyboardEvent) => {
if (event[modifierKey] && event.key === targetKey) { if (event[modifierKey] && event.key === targetKey) {
@ -15,10 +11,10 @@ const useKeyPress = (
} }
}; };
document.addEventListener("keydown", handleKeyDown); document.addEventListener('keydown', handleKeyDown);
return () => { return () => {
document.removeEventListener("keydown", handleKeyDown); document.removeEventListener('keydown', handleKeyDown);
}; };
}, [targetKey, modifierKey, callback]); }, [targetKey, modifierKey, callback]);
}; };

View File

@ -0,0 +1,24 @@
import { useState, useEffect } from "react";
function useLoadingState(
initialValue: boolean,
duration: number,
): [boolean, () => void] {
const [loading, setLoading] = useState<boolean>(initialValue);
useEffect(() => {
const timeoutId = setTimeout(() => {
setLoading(false);
}, duration);
return () => clearTimeout(timeoutId);
}, [duration]);
const resetLoading = () => {
setLoading(true);
};
return [loading, resetLoading];
}
export default useLoadingState;

View File

@ -0,0 +1,45 @@
import { Pagination } from "antd";
import { useLocation, useNavigate, useSearchParams } from "react-router-dom";
export const PaginationBody = ({ data, no_label, label_icon }: any) => {
const navigate = useNavigate();
const location = useLocation();
const pagination = location?.search || "";
const currentPage = parseInt(
new URLSearchParams(location.search).get("page") || "1",
10,
);
const pageSize = parseInt(
new URLSearchParams(location.search).get("per_page") || "8",
10,
);
const [searchParams] = useSearchParams();
const onChange = (page: number, pageSize?: number) => {
navigate(
`?page=${page}&per_page=${pageSize || data?.per_page}&search=${searchParams.get("search")}`,
{ replace: true },
);
};
const onShowSizeChange = (current: number, pageSize: number) => {
navigate(
`?page=${current}&per_page=${pageSize}&search=${searchParams.get("search")}`,
{ replace: true },
);
};
return (
<Pagination
className="text-center mt-3 paginateStyle"
total={data}
showTotal={(total: any) => `Total ${total} items`}
pageSize={pageSize}
pageSizeOptions={[8, 16, 24, 32, 40]}
defaultCurrent={currentPage}
current={currentPage} // Adding this line will set the current page correctly
onChange={onChange}
onShowSizeChange={onShowSizeChange}
/>
);
};

View File

@ -0,0 +1,72 @@
import { RiArrowLeftDownLine, RiArrowRightUpLine } from "react-icons/ri";
export const PercentageImageSrc = (percentage: number) => {
if (percentage >= 90) {
return "../ArrowType/90.png";
} else if (percentage >= 80) {
return "../ArrowType/80.png";
} else if (percentage >= 60) {
return "../ArrowType/60.png";
} else if (percentage >= 40) {
return "../ArrowType/40.png";
} else if (percentage >= 20) {
return "../ArrowType/20.png";
}
return "";
};
export const getColorName = (percentage: number) => {
if (percentage >= 6) {
return "Red";
} else if (percentage >= 4) {
return "Orange";
} else if (percentage >= 2) {
return "Green";
} else {
return "Green";
}
};
export const getStrokeColor = (percentage: number) => {
if (percentage >= 90) {
return "#87d068"; // Green color
} else if (percentage >= 80) {
return "#87d068"; // Blue color
} else if (percentage >= 60) {
return "#ffec3d"; // Yellow color
} else if (percentage >= 40) {
return "#faad14"; // Orange color
} else if (percentage >= 20) {
return "#f5222d"; // Red color
} else {
return "#f5222d"; // Red color
}
};
export const getPercentageIcon = (percentage: number) => {
if (percentage >= 60) {
return <RiArrowRightUpLine />;
} else if (percentage >= 40) {
return <></>;
} else {
return <RiArrowLeftDownLine />;
}
};
export const getPercentageText = (percentage: number) => {
if (percentage >= 60) {
return "مرتفع";
} else if (percentage >= 40) {
return "متوسط";
} else {
return "منخفض";
}
};
{
/* <RiArrowRightUpLine /> */
}
{
/* <RiArrowLeftDownLine /> */
}

View File

@ -0,0 +1,32 @@
import { useEffect, useState } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
const usePreviousPath = () => {
const location = useLocation();
const navigate = useNavigate();
const [previousPath, setPreviousPath] = useState(null);
console.log(previousPath);
useEffect(() => {
// Update the previous path whenever the location changes
const currentPath = location.pathname as any;
setPreviousPath(currentPath);
// Clean up
return () => {
setPreviousPath(null);
};
}, [location]);
const navigateToPreviousPath = () => {
if (previousPath) {
navigate(previousPath);
} else {
navigate(-1); // Fallback to default behavior
}
};
return { navigateToPreviousPath };
};
export default usePreviousPath;

View File

@ -0,0 +1,42 @@
import { useState, useEffect } from "react";
interface ResponsiveHookProps {
initialState: boolean;
setIs: any;
widthThreshold: number;
}
const useResponsive = ({
initialState,
setIs,
widthThreshold,
}: ResponsiveHookProps) => {
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
const [isBoolean, setIsBoolean] = useState<boolean>(initialState);
useEffect(() => {
const handleResize = () => {
setWindowWidth(window.innerWidth);
};
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
};
}, []);
useEffect(() => {
if (windowWidth < widthThreshold && isBoolean) {
setIs(false);
setIsBoolean(false);
} else if (windowWidth >= widthThreshold && !isBoolean) {
setIs(true);
setIsBoolean(true);
}
}, [windowWidth, isBoolean, setIs, widthThreshold]);
return { windowWidth, isBoolean, setIsBoolean };
};
export default useResponsive;

View File

@ -1,18 +1,17 @@
import { useEffect } from "react"; import { useEffect } from 'react';
import { setLocalStorageQuestions } from "../utils/setLocalStorageQuestions"; import { setLocalStorageQuestions } from '../utils/setLocalStorageQuestions';
import { setLocalStorageBaseQuestions } from '../utils/setLocalStorageBaseQuestions';
const useSaveOnDisconnect = ( const useSaveOnDisconnect = (noChange: boolean, QUESTION_OBJECT_KEY: string, SavedQuestionData: any) => {
noChange: boolean,
QUESTION_OBJECT_KEY: string,
SavedQuestionData: any,
) => {
useEffect(() => { useEffect(() => {
const handleBeforeUnload = (event: BeforeUnloadEvent) => { const handleBeforeUnload = (event: BeforeUnloadEvent) => {
console.log("disconnect"); console.log("disconnect");
if (noChange) { if (noChange) {
if (SavedQuestionData?.isBase === 1) { if(SavedQuestionData?.isBase ===1){
setLocalStorageQuestions(QUESTION_OBJECT_KEY, SavedQuestionData); setLocalStorageQuestions(QUESTION_OBJECT_KEY, SavedQuestionData);
} else {
}else{
setLocalStorageQuestions(QUESTION_OBJECT_KEY, SavedQuestionData); setLocalStorageQuestions(QUESTION_OBJECT_KEY, SavedQuestionData);
} }
} }
@ -21,22 +20,24 @@ const useSaveOnDisconnect = (
const handleOffline = () => { const handleOffline = () => {
console.log("disconnect"); console.log("disconnect");
if (noChange) { if (noChange) {
if (SavedQuestionData?.isBase === 1) { if(SavedQuestionData?.isBase ===1){
setLocalStorageQuestions(QUESTION_OBJECT_KEY, SavedQuestionData); setLocalStorageQuestions(QUESTION_OBJECT_KEY, SavedQuestionData);
} else {
}else{
setLocalStorageQuestions(QUESTION_OBJECT_KEY, SavedQuestionData); setLocalStorageQuestions(QUESTION_OBJECT_KEY, SavedQuestionData);
} }
} }
}; };
// Add event listeners // Add event listeners
window.addEventListener("beforeunload", handleBeforeUnload); window.addEventListener('beforeunload', handleBeforeUnload);
window.addEventListener("offline", handleOffline); window.addEventListener('offline', handleOffline);
// Cleanup function // Cleanup function
return () => { return () => {
window.removeEventListener("beforeunload", handleBeforeUnload); window.removeEventListener('beforeunload', handleBeforeUnload);
window.removeEventListener("offline", handleOffline); window.removeEventListener('offline', handleOffline);
}; };
}, [noChange, QUESTION_OBJECT_KEY, SavedQuestionData]); // Add dependencies to the hook }, [noChange, QUESTION_OBJECT_KEY, SavedQuestionData]); // Add dependencies to the hook
}; };

View File

@ -0,0 +1,21 @@
import { useEffect, useState } from "react";
const useSearchResults = (data: any[] | undefined, query: string | null) => {
const [results, setResults] = useState<any[]>([]);
useEffect(() => {
const filteredResults =
data?.filter((item: any) =>
item?.toLowerCase()?.includes(query?.toLowerCase()),
) ?? [];
setResults(filteredResults);
if (results?.length === 0 && query != null && query?.length > 1) {
}
}, [query]);
return results;
};
export default useSearchResults;

View File

@ -1,7 +1,7 @@
import { useEffect } from "react"; import { useEffect } from "react";
import { usePage_titleState } from "../zustand/PageTitleState"; import { usePage_titleState } from "../zustand/PageTitleState";
const useSetPageTitle = (title: any) => { const useSetPage_title = (title: any) => {
const setPage_title = usePage_titleState((state) => state.setPage_title); const setPage_title = usePage_titleState((state) => state.setPage_title);
useEffect(() => { useEffect(() => {
@ -9,4 +9,4 @@ const useSetPageTitle = (title: any) => {
}, [title, setPage_title]); }, [title, setPage_title]);
}; };
export default useSetPageTitle; export default useSetPage_title;

View File

@ -1,7 +1,7 @@
import { AppRoutes, CrudRoutes } from "../Routes"; import { AppRoutes, CrudRoutes } from "../Routes";
import { PROJECT_NAME } from "../config/AppKey"; import { PROJECT_NAME } from "../config/AppKey";
export const useGetTitleFromRoute = (path: any) => { export const usegetTitleFromRoute = (path: any) => {
if (AppRoutes[path]) { if (AppRoutes[path]) {
return `${PROJECT_NAME} | ${AppRoutes[path]}`; return `${PROJECT_NAME} | ${AppRoutes[path]}`;
} else if (CrudRoutes[path]) { } else if (CrudRoutes[path]) {

View File

@ -30,6 +30,7 @@ const FormikFormModel: React.FC<FormikFormProps> = ({
initialValues={initialValues} initialValues={initialValues}
validationSchema={validationSchema} validationSchema={validationSchema}
onSubmit={handleSubmit} onSubmit={handleSubmit}
> >
{(formik) => { {(formik) => {
useEffect(() => { useEffect(() => {
@ -42,6 +43,7 @@ const FormikFormModel: React.FC<FormikFormProps> = ({
} }
}, [isOpen]); }, [isOpen]);
return <Form className="w-100">{children}</Form>; return <Form className="w-100">{children}</Form>;
}} }}
</Formik> </Formik>

View File

@ -6,12 +6,13 @@ import { useTranslation } from "react-i18next";
import { ABILITIES_ENUM, ABILITIES_VALUES_ENUM } from "../../enums/abilities"; import { ABILITIES_ENUM, ABILITIES_VALUES_ENUM } from "../../enums/abilities";
import { hasAbility } from "../../utils/hasAbility"; import { hasAbility } from "../../utils/hasAbility";
export { export {
SearchField, SearchField,
useModalHandler, useModalHandler,
ModalEnum, ModalEnum,
useTranslation, useTranslation,
ABILITIES_ENUM, ABILITIES_ENUM,
ABILITIES_VALUES_ENUM, ABILITIES_VALUES_ENUM,
hasAbility, hasAbility
}; };

View File

@ -1,5 +1,5 @@
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { useGetTitleFromRoute } from "../../Hooks/useGetTitleFromRoute"; import { usegetTitleFromRoute } from "../../Hooks/usegetTitleFromRoute";
import { Helmet } from "react-helmet"; import { Helmet } from "react-helmet";
import { useLocation } from "react-router-dom"; import { useLocation } from "react-router-dom";
import NavBar from "./NavBar"; import NavBar from "./NavBar";
@ -18,7 +18,7 @@ const Layout = ({
return ( return (
<> <>
<Helmet> <Helmet>
<title>{useGetTitleFromRoute(location.pathname)}</title> <title>{usegetTitleFromRoute(location.pathname)}</title>
</Helmet> </Helmet>
<div className="Layout"> <div className="Layout">
<main className={`${className} Layout_Body`}> <main className={`${className} Layout_Body`}>

View File

@ -79,9 +79,8 @@ const SideBar = () => {
return ( return (
<div className="side_bar"> <div className="side_bar">
<h1> <h1>
{/* {t("sidebar.dashboard")} */} {/* {t("sidebar.dashboard")} */}
{branch_name}{" "} {branch_name} </h1>
</h1>
<Divider /> <Divider />
<div className="side_bar_links"> <div className="side_bar_links">
{menuItems.map((item, index) => { {menuItems.map((item, index) => {

View File

@ -20,11 +20,13 @@ type FormFieldType = {
}; };
const FormField = ({ isLoading }: FormFieldType) => { const FormField = ({ isLoading }: FormFieldType) => {
const [t] = useTranslation(); const [t] = useTranslation();
return ( return (
<Form className="AuthForm"> <Form className="AuthForm">
<Image src="../App/Logo.png" /> <Image src="../App/Logo.png" />
<div className="AuthInput"> <div className="AuthInput">
<label className="form-label" htmlFor="username"> <label className="form-label" htmlFor="username">
{t("input.Username")} {t("input.Username")}

View File

@ -13,6 +13,7 @@ const LoginForm = () => {
const { mutate, isLoading, isSuccess, data } = useLoginAdmin(); const { mutate, isLoading, isSuccess, data } = useLoginAdmin();
const [t] = useTranslation(); const [t] = useTranslation();
const handelSubmit = (values: FormValues) => { const handelSubmit = (values: FormValues) => {
mutate(values); mutate(values);
}; };

View File

@ -2,14 +2,14 @@ import React from "react";
import Image from "../../Components/Ui/Image"; import Image from "../../Components/Ui/Image";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { ABILITIES_ENUM } from "../../enums/abilities"; import { ABILITIES_ENUM } from "../../enums/abilities";
import useSetPageTitle from "../../Hooks/useSetPageTitle"; import useSetPage_title from "../../Hooks/useSetPageTitle";
const Dummy = () => { const Dummy = () => {
const [t] = useTranslation(); const [t] = useTranslation();
useSetPageTitle(`${t(ABILITIES_ENUM?.MAIN_PAGE)} / ${t("dashboard")}`); useSetPage_title(`${t(ABILITIES_ENUM?.MAIN_PAGE)} / ${t("dashboard")}`);
return ( return (
<div className="DummyHomePage"> <div className="DammyHomePage">
<Image src="/App/SyriaLogo.webp" /> <Image src="/App/SyriaLogo.webp" />
</div> </div>
); );

19
src/Pages/Home/Page.tsx Normal file
View File

@ -0,0 +1,19 @@
import ChartSection from "./Section/ChartSection";
import NoteSections from "./Section/NoteSections";
import { useTranslation } from "react-i18next";
import { ABILITIES_ENUM } from "../../enums/abilities";
// import useSetPage_title from "../../Hooks/useSetPageTitle";
const Page = () => {
const [t] = useTranslation();
// useSetPage_title(`${t(ABILITIES_ENUM?.MAIN_PAGE)} / ${t("dashboard")}`);
return (
<div className="HomePage">
<ChartSection />
<NoteSections />
</div>
);
};
export default Page;

View File

@ -0,0 +1,26 @@
import React from "react";
import CountSection from "../../../Components/Home/CountSection";
import ColumnChart from "../../../Components/Chart/ColumnChart";
import AreaChart from "../../../Components/Chart/AreaChart";
import StudentSubjects from "../../../Components/Home/StudentSubjects";
import CalendarSection from "../../../Components/Home/CalendarSection";
const ChartSection = () => {
return (
<div className="ChartSection">
<CountSection />
<div className="TowItem">
<ColumnChart />
<CalendarSection />
</div>
<AreaChart />
<div className="TowItem">
<StudentSubjects />
<ColumnChart />
</div>
</div>
);
};
export default ChartSection;

View File

@ -0,0 +1,14 @@
import React from "react";
import NoteSection from "../../../Components/Home/NoteSection";
import ActivitySection from "../../../Components/Home/ActivitySection";
const NoteSections = () => {
return (
<div className="NoteSections">
<NoteSection />
<ActivitySection />
</div>
);
};
export default NoteSections;

View File

@ -24,7 +24,9 @@ const Form = () => {
<ValidationField placeholder="name" label="name" name="name" /> <ValidationField placeholder="name" label="name" name="name" />
</Col> </Col>
<div> <div>
<DynamicTags /> <DynamicTags/>
</div> </div>
</Row> </Row>
); );

View File

@ -23,8 +23,9 @@ const ModalForm: React.FC = () => {
}, [setIsOpen, isSuccess]); }, [setIsOpen, isSuccess]);
const handleSubmit = (values: any) => { const handleSubmit = (values: any) => {
mutate({ mutate({
...values, ...values
}); });
}; };

View File

@ -6,13 +6,16 @@ import { useEffect } from "react";
import DynamicTags from "../synonyms/DynamicTags"; import DynamicTags from "../synonyms/DynamicTags";
const Form = () => { const Form = () => {
return ( return (
<Row className="w-100"> <Row className="w-100">
<Col> <Col>
<ValidationField placeholder="name" label="name" name="name" /> <ValidationField placeholder="name" label="name" name="name" />
</Col> </Col>
<div> <div>
<DynamicTags /> <DynamicTags/>
</div> </div>
</Row> </Row>
); );

View File

@ -12,7 +12,9 @@ import ModelButtons from "../../../Components/models/ModelButtons";
const ModalForm: React.FC = () => { const ModalForm: React.FC = () => {
const { isOpen, setIsOpen } = useModalState((state) => state); const { isOpen, setIsOpen } = useModalState((state) => state);
const { objectToEdit, setObjectToEdit } = useObjectToEdit((state) => state); const { objectToEdit, setObjectToEdit } = useObjectToEdit(
(state) => state,
);
const { mutate, isSuccess, isLoading } = useUpdateTag(); const { mutate, isSuccess, isLoading } = useUpdateTag();
// console.log(objectToEdit,"objectToEdit"); // console.log(objectToEdit,"objectToEdit");
const handleSubmit = (values: any) => { const handleSubmit = (values: any) => {
@ -20,7 +22,7 @@ const ModalForm: React.FC = () => {
// phone_number: values?.number // phone_number: values?.number
// }); // });
mutate({ mutate({
...values, ...values
}); });
}; };
const handleCancel = () => { const handleCancel = () => {
@ -56,6 +58,7 @@ const ModalForm: React.FC = () => {
<main className="main_modal w-100"> <main className="main_modal w-100">
<ModelBody /> <ModelBody />
<ModelButtons isLoading={isLoading} /> <ModelButtons isLoading={isLoading} />
</main> </main>
</FormikForm> </FormikForm>
)} )}

View File

@ -1,47 +1,47 @@
import { FaPlus } from "react-icons/fa"; 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 useSetPageTitle from "../../Hooks/useSetPageTitle"; // import useSetPage_title from "../../Hooks/useSetPageTitle";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { lazy, Suspense } from "react"; import { lazy, Suspense } from 'react';
import { Spin } from "antd"; import { Spin } from "antd";
import { canAddTags } from "../../utils/hasAbilityFn"; import { canAddTags } from "../../utils/hasAbilityFn";
import useSetPageTitle from "../../Hooks/useSetPageTitle"; import useSetPage_title from "../../Hooks/useSetPageTitle";
const Table = lazy(() => import("./Table")); const Table = lazy(() => import('./Table'));
const AddModalForm = lazy(() => import("./Model/AddModel")); const AddModalForm = lazy(() => import('./Model/AddModel'));
const EditModalForm = lazy(() => import("./Model/EditModel")); const EditModalForm = lazy(() => import('./Model/EditModel'));
const DeleteModalForm = lazy(() => import("./Model/Delete")); const DeleteModalForm = lazy(() => import('./Model/Delete'));
const SearchField = lazy( const SearchField = lazy(() => import('../../Components/DataTable/SearchField'));
() => import("../../Components/DataTable/SearchField"),
);
const TableHeader = () => { const TableHeader = () => {
const { handel_open_model } = useModalHandler(); const { handel_open_model } = useModalHandler();
const [t] = useTranslation(); const [t] = useTranslation();
useSetPageTitle(t(`page_header.tags`)); useSetPage_title(
t(`page_header.tags`),
);
return ( return (
<div className="TableWithHeader"> <div className="TableWithHeader">
<Suspense fallback={<Spin />}>
<header className="d-flex justify-content-between">
<SearchField
searchBy="name"
placeholder={t("practical.search_here")}
/>
{canAddTags && ( <Suspense fallback={<Spin/>}>
<div className="Selects"> <header className="d-flex justify-content-between">
<button <SearchField searchBy="name" placeholder={t("practical.search_here")} />
onClick={() => handel_open_model(ModalEnum?.TAGS_ADD)}
className="add_button" {canAddTags && (
> <div className="Selects">
{t("models.tags")} <FaPlus /> <button
</button> onClick={() => handel_open_model(ModalEnum?.TAGS_ADD)}
</div> className="add_button"
)} >
</header> {t("models.tags")} <FaPlus />
</button>
</div>
)}
</header>
<Table /> <Table />
<DeleteModalForm /> <DeleteModalForm />

View File

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

View File

@ -13,5 +13,5 @@ export {
AddModalForm, AddModalForm,
EditModalForm, EditModalForm,
DeleteModalForm, DeleteModalForm,
FaPlus, FaPlus
}; };

View File

@ -1,56 +1,70 @@
import { useFormikContext } from "formik"; import { useFormikContext } from 'formik'
import React from "react"; import React from 'react'
import { useTranslation } from "react-i18next"; import { useTranslation } from 'react-i18next'
import { FaCirclePlus } from "react-icons/fa6"; import { FaCirclePlus } from 'react-icons/fa6'
import Tag from "./Tag"; import Tag from './Tag'
const DynamicTags = () => { const DynamicTags = () => {
const formik = useFormikContext<any>();
const [t] = useTranslation();
console.log(formik?.values?.synonyms); const formik = useFormikContext<any>()
const [t] = useTranslation()
console.log(formik?.values?.synonyms);
const handleAddChoice = () => { const handleAddChoice = () => {
const length = formik?.values?.synonyms.length; const length = formik?.values?.synonyms.length;
const lastElement = formik?.values?.synonyms[length - 1]; const lastElement = formik?.values?.synonyms[length - 1];
if (lastElement !== "") { if(lastElement !== ""){
formik.setFieldValue("synonyms", [ formik.setFieldValue('synonyms', [...(formik?.values as any)?.synonyms as any[],""])
...((formik?.values as any)?.synonyms as any[]), }else{
"",
]);
} else {
} }
};
// console.log(formik?.values);
// console.log(currentTag); }
// console.log(formik?.values);
// console.log(currentTag);
return ( return (
<div className="DynamicTags"> <div className='DynamicTags'>
{formik?.values?.synonyms?.length < 1 && ( {formik?.values?.synonyms?.length < 1 &&
<p className="add_new_button">
<FaCirclePlus size={23} onClick={handleAddChoice} />{" "}
{t("header.add_synonyms")}
</p>
)}
<div className="tag_container"> <p className="add_new_button" >
<div className="tags"> <FaCirclePlus size={23} onClick={handleAddChoice} /> {t("header.add_synonyms")}
{(((formik?.values as any)?.synonyms as any[]) || []).map( </p>
(item: any, index: number) => { }
return <Tag key={index} index={index} data={item} />;
},
)}
</div>
{formik?.values?.synonyms?.length > 0 && ( <div className="tag_container">
<p className="add_new_button"> <div className="tags">
<FaCirclePlus onClick={handleAddChoice} size={20} />
</p> {
)} (((formik?.values as any)?.synonyms as any[])||[]) .map((item:any,index:number)=>{
</div>
return (
<Tag key={index} index={index} data={item}/>
)
}
)
}
</div>
{formik?.values?.synonyms?.length > 0 &&
<p className="add_new_button" >
<FaCirclePlus onClick={handleAddChoice} size={20} />
</p>
}
</div>
</div> </div>
); )
}; }
export default DynamicTags; export default DynamicTags

View File

@ -1,60 +1,66 @@
import { useFormikContext } from "formik"; import { useFormikContext } from 'formik';
import React, { useRef, useEffect } from "react"; import React, { useRef, useEffect } from 'react';
import { useObjectToEdit } from "../../../zustand/ObjectToEditState"; import { useObjectToEdit } from '../../../zustand/ObjectToEditState';
import { FaTrash } from "react-icons/fa"; import { FaTrash } from 'react-icons/fa';
const Tag = ({ data, index }: { data: any; index: number }) => { const Tag = ({ data, index }: { data: any, index: number }) => {
const inputRef = useRef<HTMLInputElement>(null); const inputRef = useRef<HTMLInputElement>(null);
const formik = useFormikContext<any>(); const formik = useFormikContext<any>();
const { setTagsSearch, setCurrentTag } = useObjectToEdit(); const { setTagsSearch ,setCurrentTag} = useObjectToEdit();
useEffect(() => { useEffect(() => {
if (inputRef.current) { if (inputRef.current) {
inputRef.current.style.width = `${(formik?.values?.synonyms[index]?.length + 1) * 8}px`; inputRef.current.style.width = `${(formik?.values?.synonyms[index]?.length + 1) * 8}px`;
} }
}, [formik?.values?.synonyms[index]]); }, [formik?.values?.synonyms[index]]);
console.log(formik?.values?.synonyms); console.log(formik?.values?.synonyms);
console.log(index); console.log(index);
const handleEditInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
// console.log(e.target.value);
formik.setFieldValue(`synonyms[${index}]`, e.target.value);
setTagsSearch(e.target.value);
setCurrentTag(index);
};
const handleInputBlur = () => { const handleEditInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
// setTagsSearch(null) // console.log(e.target.value);
}; formik.setFieldValue(`synonyms[${index}]`, e.target.value);
setTagsSearch(e.target.value)
setCurrentTag(index)
const handleDeleteChoice = () => { };
console.log(data);
// Create a copy of current tags array
const currentTags = [...formik.values.synonyms];
// 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 const handleInputBlur = () => {
formik.setFieldValue("synonyms", currentTags); // setTagsSearch(null)
};
// Reset search state if needed const handleDeleteChoice = () => {
setTagsSearch(null); console.log(data);
}; // Create a copy of current tags array
const currentTags = [...formik.values.synonyms];
// Remove the item at the specified index from the array
currentTags.splice(index, 1);
console.log(currentTags); // Log the updated tags array
return ( // Update formik field value with the updated tags array
<div className="tag"> formik.setFieldValue('synonyms', currentTags);
<input
ref={inputRef} // Reset search state if needed
className="tagInput" setTagsSearch(null);
type="text" };
value={formik?.values?.synonyms[index]}
onChange={handleEditInputChange} return (
onBlur={handleInputBlur} <div className='tag'>
/> <input
<FaTrash onClick={handleDeleteChoice} /> ref={inputRef}
</div> className="tagInput"
); type="text"
value={formik?.values?.synonyms[index]}
onChange={handleEditInputChange}
onBlur={handleInputBlur}
/>
<FaTrash onClick={handleDeleteChoice}/>
</div>
);
}; };
export default Tag; export default Tag;

View File

@ -19,6 +19,8 @@ export const useColumns = () => {
}; };
const [t] = useTranslation(); const [t] = useTranslation();
const columns: TableColumnsType<tags> = [ const columns: TableColumnsType<tags> = [
{ {
title: t("columns.id"), title: t("columns.id"),
@ -55,10 +57,16 @@ export const useColumns = () => {
placement="top" placement="top"
title={t("practical.edit")} title={t("practical.edit")}
color="#E0E0E0" color="#E0E0E0"
> >
<span onClick={() => handleEdit(record)}> <span onClick={() => handleEdit(record)}>
<MdOutlineEdit size={22} style={{ color: "#A098AE" }} /> <MdOutlineEdit
size={22}
style={{ color: "#A098AE" }}
/>
</span> </span>
</Tooltip> </Tooltip>
)} )}

View File

@ -1,42 +1,49 @@
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { lazy, Suspense } from "react"; import { lazy, Suspense } from 'react';
import { Spin } from "antd"; import { Spin } from "antd";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { ParamsEnum } from "../../enums/params"; import { ParamsEnum } from "../../enums/params";
import { useGetAllSubject } from "../../api/subject"; import { useGetAllSubject } from "../../api/subject";
import useSetPageTitle from "../../Hooks/useSetPageTitle"; import useSetPage_title from "../../Hooks/useSetPageTitle";
const Table = lazy(() => import("./Table")); const Table = lazy(() => import('./Table'));
const AddModalForm = lazy(() => import("./Model/AddModel")); const AddModalForm = lazy(() => import('./Model/AddModel'));
const EditModalForm = lazy(() => import("./Model/EditModel")); const EditModalForm = lazy(() => import('./Model/EditModel'));
const DeleteModels = lazy(() => import("./Model/Delete")); const DeleteModels = lazy(() => import('./Model/Delete'));
const TableHeader = () => { const TableHeader = () => {
const [t] = useTranslation(); const [t] = useTranslation();
const { subject_id } = useParams<ParamsEnum>(); const { subject_id} = useParams<ParamsEnum>();
const { data: Subject } = useGetAllSubject({ const { data: Subject } = useGetAllSubject({
show: subject_id, show:subject_id
}); });
const SubjectName = Subject?.data?.name ?? ""; const SubjectName = Subject?.data?.name ?? "";
useSetPageTitle(t(`page_header.subject`) + "/" + t(`${SubjectName}`)); useSetPage_title(
t(`page_header.subject`) +
"/" +
t(`${SubjectName}`),
);
return ( return (
<div className="TableWithHeader"> <div className="TableWithHeader">
<Suspense fallback={<Spin />}> <Suspense fallback={<Spin/>}>
<header> <header>
<h6> <h6>
{t("models.units")} {SubjectName} {t("models.units")} {SubjectName}
</h6> </h6>
</header>
</header>
<Table /> <Table />
<AddModalForm /> <AddModalForm />
<EditModalForm /> <EditModalForm />
<DeleteModels /> <DeleteModels />
</Suspense> </Suspense>
</div> </div>
); );
}; };

View File

@ -7,9 +7,9 @@ import { useParams } from "react-router-dom";
import { ParamsEnum } from "../../enums/params"; import { ParamsEnum } from "../../enums/params";
const App: React.FC = () => { const App: React.FC = () => {
const { subject_id } = useParams<ParamsEnum>(); const {subject_id} = useParams<ParamsEnum>()
const response = useGetAllUnit({ subject_id: subject_id, pagination: true }); const response = useGetAllUnit({subject_id:subject_id, pagination: true});
console.log(response?.data?.data, "response?.data"); console.log(response?.data?.data,"response?.data");
return <DataTable response={response} useColumns={useColumns} />; return <DataTable response={response} useColumns={useColumns} />;
}; };

View File

@ -10,23 +10,20 @@ import { useTranslation } from "react-i18next";
import { ABILITIES_ENUM } from "../../enums/abilities"; import { ABILITIES_ENUM } from "../../enums/abilities";
import { BsEyeFill } from "react-icons/bs"; import { BsEyeFill } from "react-icons/bs";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { import { canAddUnit, canDeleteUnit, canEditUnit, canShowUnit } from "../../utils/hasAbilityFn";
canAddUnit,
canDeleteUnit,
canEditUnit,
canShowUnit,
} from "../../utils/hasAbilityFn";
export const useColumns = () => { export const useColumns = () => {
const { handel_open_model } = useModalHandler(); const { handel_open_model } = useModalHandler();
const { setObjectToEdit } = useObjectToEdit((state) => state); const { setObjectToEdit } = useObjectToEdit((state) => state);
const navigate = useNavigate(); const navigate = useNavigate()
const handelShow = (record: any) => { const handelShow = (record: any) => {
navigate(`${ABILITIES_ENUM?.UNIT}/${record?.id}`); navigate(`${ABILITIES_ENUM?.UNIT}/${record?.id}`);
}; };
const handelDelete = (data: any) => { const handelDelete = (data: any) => {
setObjectToEdit(data); setObjectToEdit(data);
handel_open_model(ModalEnum?.UNIT_DELETE); handel_open_model(ModalEnum?.UNIT_DELETE);
@ -89,7 +86,11 @@ export const useColumns = () => {
color="#E0E0E0" color="#E0E0E0"
> >
<span onClick={() => handleEdit(record)}> <span onClick={() => handleEdit(record)}>
<MdOutlineEdit size={22} style={{ color: "#A098AE" }} /> <MdOutlineEdit
size={22}
style={{ color: "#A098AE" }}
/>
</span> </span>
</Tooltip> </Tooltip>
)} )}
@ -100,13 +101,16 @@ export const useColumns = () => {
style={{ color: "#C11313" }} style={{ color: "#C11313" }}
/> />
)} )}
{canShowUnit && ( {canShowUnit && (
<BsEyeFill <BsEyeFill
onClick={() => handelShow(record)} onClick={() => handelShow(record)}
size={22} size={22}
style={{ color: "green" }} style={{ color: "green" }}
/> />
)}
)}
</Space> </Space>
); );
}, },

View File

@ -20,6 +20,7 @@ const Form = () => {
<Col> <Col>
<ValidationField name="name" label="name" /> <ValidationField name="name" label="name" />
</Col> </Col>
</Row> </Row>
); );
}; };

View File

@ -20,7 +20,7 @@ const ModalForm: React.FC = () => {
const { mutate, isSuccess, isLoading } = useAddLesson(); const { mutate, isSuccess, isLoading } = useAddLesson();
const { unit_id } = useParams<ParamsEnum>(); const {unit_id} = useParams<ParamsEnum>()
useEffect(() => { useEffect(() => {
if (isSuccess) { if (isSuccess) {
setIsOpen(""); setIsOpen("");

Some files were not shown because too many files have changed in this diff Show More