-
-
-
+
+
+
+
+
- {isAllProjectsSelected && (
)}
+
+
+
+
+
+ {!isAllProjectsSelected && (
+
+ )}
+
+
+
+
+
+
);
};
diff --git a/src/components/Dashboard/ExpenseByProject.jsx b/src/components/Dashboard/ExpenseByProject.jsx
new file mode 100644
index 00000000..e3c79113
--- /dev/null
+++ b/src/components/Dashboard/ExpenseByProject.jsx
@@ -0,0 +1,162 @@
+import React, { useState, useEffect } from "react";
+import Chart from "react-apexcharts";
+import { useExpenseType } from "../../hooks/masterHook/useMaster";
+import { useSelector } from "react-redux";
+import { useExpenseDataByProject } from "../../hooks/useDashboard_Data";
+import { formatCurrency } from "../../utils/appUtils";
+import { formatDate_DayMonth } from "../../utils/dateUtils";
+
+const ExpenseByProject = () => {
+ const projectId = useSelector((store) => store.localVariables.projectId);
+ const [range, setRange] = useState("12M");
+ const [selectedType, setSelectedType] = useState("");
+ const [viewMode, setViewMode] = useState("Category");
+ const [chartData, setChartData] = useState({ categories: [], data: [] });
+
+ const { ExpenseTypes, loading: typeLoading } = useExpenseType();
+
+ const { data: expenseApiData, isLoading } = useExpenseDataByProject(
+ projectId,
+ selectedType,
+ range === "All" ? null : parseInt(range)
+ );
+
+ useEffect(() => {
+ if (expenseApiData) {
+ const categories = expenseApiData.map(
+ (item) => formatDate_DayMonth(item.monthName, item.year)
+ );
+ const data = expenseApiData.map((item) => item.total);
+ setChartData({ categories, data });
+ } else {
+ setChartData({ categories: [], data: [] });
+ }
+ }, [expenseApiData]);
+
+ const getSelectedTypeName = () => {
+ if (!selectedType) return "All Types";
+ const found = ExpenseTypes.find((t) => t.id === selectedType);
+ return found ? found.name : "All Types";
+ };
+
+ const options = {
+ chart: { type: "bar", toolbar: { show: false } },
+ plotOptions: { bar: { horizontal: false, columnWidth: "55%", borderRadius: 4 } },
+ dataLabels: { enabled: true, formatter: (val) => formatCurrency(val) },
+ xaxis: {
+ categories: chartData.categories,
+ labels: { style: { fontSize: "12px" }, rotate: -45 },
+ },
+ tooltip: {
+ y: {
+ formatter: (val) => `${formatCurrency(val)} (${getSelectedTypeName()})`,
+ },
+ },
+
+ annotations: { xaxis: [{ x: 0, strokeDashArray: 0, }] },
+ fill: { opacity: 1 },
+ colors: ["#2196f3"],
+ };
+
+ const series = [
+ {
+ name: getSelectedTypeName(),
+ data: chartData.data,
+ },
+ ];
+
+ return (
+
+ {/* Header */}
+
+
+
+
Monthly Expense -
+
Detailed project expenses
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+ {viewMode === "Category" && (
+
+ )}
+
+
+ {/* Range Buttons + Expense Dropdown */}
+
+ {["1M", "3M", "6M", "12M", "All"].map((item) => (
+
+ ))}
+
+
+
+ {/* Chart */}
+
+ {isLoading ? (
+
Loading chart...
+ ) : (
+
+ )}
+
+
+ );
+};
+
+export default ExpenseByProject;
\ No newline at end of file
diff --git a/src/hooks/useDashboard_Data.jsx b/src/hooks/useDashboard_Data.jsx
index 747d2f5b..48be991f 100644
--- a/src/hooks/useDashboard_Data.jsx
+++ b/src/hooks/useDashboard_Data.jsx
@@ -282,4 +282,15 @@ export const useExpenseStatus = (projectId)=>{
return resp.data;
}
})
-}
\ No newline at end of file
+}
+
+export const useExpenseDataByProject = (projectId, categoryId, months) => {
+ return useQuery({
+ queryKey: ["expenseByProject", projectId, categoryId, months],
+ queryFn: async () => {
+ const resp = await GlobalRepository.getExpenseDataByProject(projectId, categoryId, months);
+ return resp.data;
+ },
+
+ });
+};
\ No newline at end of file
diff --git a/src/pages/Expense/ExpensePage.jsx b/src/pages/Expense/ExpensePage.jsx
index 2141af2c..1206e237 100644
--- a/src/pages/Expense/ExpensePage.jsx
+++ b/src/pages/Expense/ExpensePage.jsx
@@ -129,9 +129,7 @@ const ExpensePage = () => {