diff --git a/src/App.jsx b/src/App.jsx index 6a05ceb..ffe69c2 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -38,6 +38,7 @@ import { MyBlogs, Error, CourseFinancialAid, + MangeFinancialAidRequests, } from "./pages"; import { action as updateProfileInfoAction } from "./components/userProfile/profileSettings/UpdateProfileInfo"; @@ -121,6 +122,7 @@ const router = createBrowserRouter([ { path: "/signup", element: , + errorElement: , }, { path: "/login", @@ -195,6 +197,10 @@ const router = createBrowserRouter([ path: "paymentsrecords", element: , }, + { + path: "financial-aid-requests", + element: , + }, ], }, ]); diff --git a/src/components/dashboard/FinancialAidRequestElement.jsx b/src/components/dashboard/FinancialAidRequestElement.jsx new file mode 100644 index 0000000..6d4ac96 --- /dev/null +++ b/src/components/dashboard/FinancialAidRequestElement.jsx @@ -0,0 +1,127 @@ +import { toast } from "react-toastify"; +import { customFetch } from "../../utils/customFetch"; + +import TableBody from "./shard/TableBody"; +import TableBodyCell from "./shard/TableBodyCell"; + +const FinancialAidRequestElement = ({ request, token, setIsChanged }) => { + const { + _id, + age, + education, + employmentStatus, + course, + user, + applicationStatus, + createdAt, + updatedAt, + } = request; + const formatCreatedAtDate = new Date(createdAt).toLocaleDateString(); + + const handleApprove = async () => { + const confirm = window.confirm( + "Are you sure you want to approve this financial aid request?" + ); + if (!confirm) return; + try { + await customFetch.patch( + `admin/approveFinancialAidRequest/${_id}`, + {}, + { + headers: { + Authorization: `Bearer ${token}`, + }, + } + ); + setIsChanged(true); + toast.success("Financial application approved successfully"); + } catch (error) { + toast.error(error.response.data.message); + } + }; + + const handleReject = async () => { + const confirm = window.confirm( + "Are you sure you want to reject this financial aid request?" + ); + if (!confirm) return; + try { + await customFetch.patch( + `admin/rejectFinancialAidRequest/${_id}`, + {}, + { + headers: { + Authorization: `Bearer ${token}`, + }, + } + ); + setIsChanged(true); + toast.success("Financial Aid application rejected successfully"); + } catch (error) { + toast.error(error.response.data.message); + } + }; + + const handleDelete = async () => { + const confirm = window.confirm( + "Are you sure you want to delete this financial aid Request?" + ); + if (!confirm) return; + try { + await customFetch.delete(`admin/deleteFinancialAidRequest/${_id}`, { + headers: { + Authorization: `Bearer ${token}`, + }, + }); + + setIsChanged(true); + toast.success("Financial Aid application deleted successfully"); + } catch (error) { + toast.error(error.response.data.message); + } + }; + + return ( + + {_id} + {user.name} + {user.email} + {age} + {education} + {employmentStatus} + {course.title} + {formatCreatedAtDate} + {applicationStatus} + + +
+ + + +
+
+
+ ); +}; + +export default FinancialAidRequestElement; diff --git a/src/components/dashboard/FinancialAidRequestHeader.jsx b/src/components/dashboard/FinancialAidRequestHeader.jsx new file mode 100644 index 0000000..bb33e72 --- /dev/null +++ b/src/components/dashboard/FinancialAidRequestHeader.jsx @@ -0,0 +1,21 @@ +import TableHeader from "./shard/TableHeader"; +import TableHeaderCell from "./shard/TableHeaderCell"; + +const FinancialAidRequestHeader = () => { + return ( + + Request-ID + Name + Email + Age + Education + Employment-Status + Course-Title + Created At + Application-Status + Actions + + ); +}; + +export default FinancialAidRequestHeader; diff --git a/src/components/index.js b/src/components/index.js index f04f5c0..f282cb7 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -67,6 +67,9 @@ export { default as InstructorElement } from "./dashboard/InstructorElement"; export { default as InstructorRequestsHeader } from "./dashboard/InstructorRequestsHeader"; export { default as InstructorsApplicationElement } from "./dashboard/InstructorsApplicationElement"; +export { default as FinancialAidRequestHeader } from "./dashboard/FinancialAidRequestHeader"; +export { default as FinancialAidRequestElement } from "./dashboard/FinancialAidRequestElement"; + export { default as StatsBox } from "./dashboard/StatsBox"; export { default as StatsContainer } from "./dashboard/StatsContainer"; diff --git a/src/layout/dashboard/DashboardNavBar.jsx b/src/layout/dashboard/DashboardNavBar.jsx index c34fbe2..4896c7d 100644 --- a/src/layout/dashboard/DashboardNavBar.jsx +++ b/src/layout/dashboard/DashboardNavBar.jsx @@ -54,6 +54,10 @@ function DashboardNavBar() { path="/dashboard/paidCourses" navText="Paid Courses" /> + + {/* financial aid request*/} + + {/* Add Courses */} - {/* Settings */} - - {/* Payments */} + {/* Settings */} + ); diff --git a/src/pages/dashboard/ManageInstructorsRequests.jsx b/src/pages/dashboard/ManageInstructorsRequests.jsx index da87f04..8f09650 100644 --- a/src/pages/dashboard/ManageInstructorsRequests.jsx +++ b/src/pages/dashboard/ManageInstructorsRequests.jsx @@ -73,9 +73,11 @@ const ManageInstructorsRequests = () => { {loading ? ( -
-

Loading...

-
+ + + No Courses Found + + ) : error ? (

{error}

diff --git a/src/pages/dashboard/MangeFinancialAidRequests.jsx b/src/pages/dashboard/MangeFinancialAidRequests.jsx new file mode 100644 index 0000000..062e59e --- /dev/null +++ b/src/pages/dashboard/MangeFinancialAidRequests.jsx @@ -0,0 +1,107 @@ +import { useEffect, useState } from "react"; +import { useSelector } from "react-redux"; +import { customFetch } from "../../utils/customFetch"; + +import { + PageIntro, + PageContainer, + FinancialAidRequestHeader, + FinancialAidRequestElement, + Pagination, +} from "../../components"; + +const MangeFinancialAidRequests = () => { + const { token } = useSelector((state) => state.userReducers); + const [financialAidRequests, setFinancialAidRequests] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const [isChanged, setIsChanged] = useState(false); + const [currentPage, setCurrentPage] = useState(1); + const [itemsPerPage, setItemsPerPage] = useState(15); + const [isMorePages, setIsMorePages] = useState(false); + + useEffect(() => { + const fetchFinancialAidRequests = async () => { + setLoading(true); + setError(null); + try { + const response = await customFetch.get( + "admin/getAllFinancialAidRequests", + { + headers: { + Authorization: `Bearer ${token}`, + }, + params: { + page: currentPage, + limit: itemsPerPage, + }, + } + ); + + const fetchedFinancialAidsApplications = + response.data.data.financialAidRequests; + + if (fetchedFinancialAidsApplications.length < itemsPerPage) { + setIsMorePages(false); + } else { + setIsMorePages(true); + } + + setFinancialAidRequests(fetchedFinancialAidsApplications); + } catch (error) { + setError( + error.message || "Failed to fetch Financial Aids Applications " + ); + } finally { + setLoading(false); + setIsChanged(false); + } + }; + + fetchFinancialAidRequests(); + }, [token, isChanged, currentPage, itemsPerPage]); + + return ( +
+ + + + {loading ? ( + + + Loading Financial Aids Requests...... + + + ) : error ? ( +
+

{error}

+
+ ) : financialAidRequests.length > 0 ? ( + financialAidRequests.map((request, index) => ( + + )) + ) : ( +
+

+ No Financial Aid Requests were requested +

+
+ )} +
+ setCurrentPage((prev) => prev - 1)} + onNextPage={() => setCurrentPage((prev) => prev + 1)} + /> +
+ ); +}; + +export default MangeFinancialAidRequests; diff --git a/src/pages/index.js b/src/pages/index.js index 5d80bee..772db6e 100644 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -30,6 +30,7 @@ export { default as CreateInstructorAccount } from "./dashboard/CreateInstructor export { default as ManageInstructorsRequests } from "./dashboard/ManageInstructorsRequests"; export { default as ManageBlogs } from "./dashboard/ManageBlogs"; export { default as ManagePayments } from "./dashboard/ManagePayments"; +export { default as MangeFinancialAidRequests } from "./dashboard/MangeFinancialAidRequests"; //userProfile export { default as Profile } from "./userProfile/Profile";