@@ -88,27 +85,15 @@ const AttendanceOverview = () => {
Role-wise present count
-
@@ -127,9 +112,7 @@ const AttendanceOverview = () => {
| Role |
{dates.map((date, idx) => (
-
- {date}
- |
+ {date} |
))}
@@ -152,4 +135,4 @@ const AttendanceOverview = () => {
);
};
-export default AttendanceOverview;
\ No newline at end of file
+export default AttendanceOverview;
diff --git a/src/components/Dashboard/Dashboard.jsx b/src/components/Dashboard/Dashboard.jsx
index bef66711..362b53da 100644
--- a/src/components/Dashboard/Dashboard.jsx
+++ b/src/components/Dashboard/Dashboard.jsx
@@ -14,34 +14,32 @@ import { useDispatch, useSelector } from "react-redux";
// import ProjectProgressChart from "./ProjectProgressChart";
// import ProjectOverview from "../Project/ProjectOverview";
import AttendanceOverview from "./AttendanceChart";
-import ExpenseChartDesign2 from "./ExpenseChartDesign2";
+import ExpenseChartDesign from "./ExpenseChartDesign";
const Dashboard = () => {
-
// const { projectsCardData } = useDashboardProjectsCardData();
// const { teamsCardData } = useDashboardTeamsCardData();
// const { tasksCardData } = useDashboardTasksCardData();
- // Get the selected project ID from Redux store
- const projectId = useSelector((store) => store.localVariables.projectId);
- const isAllProjectsSelected = projectId === null;
+ // Get the selected project ID from Redux store
+ const projectId = useSelector((store) => store.localVariables.projectId);
+ const isAllProjectsSelected = projectId === null;
- return (
-
-
-
-
-
-
-
- {!isAllProjectsSelected && (
-
-
{/* Removed unnecessary projectId prop */}
-
- )}
-
+ return (
+
+
+
+
- );
+
+ {!isAllProjectsSelected && (
+
+
{/* Removed unnecessary projectId prop */}
+
+ )}
+
+
+ );
};
export default Dashboard;
diff --git a/src/components/Dashboard/ExpenseChartDesign.jsx b/src/components/Dashboard/ExpenseChartDesign.jsx
new file mode 100644
index 00000000..b9ec9f91
--- /dev/null
+++ b/src/components/Dashboard/ExpenseChartDesign.jsx
@@ -0,0 +1,142 @@
+import React, { useEffect, useState } from "react";
+import Chart from "react-apexcharts";
+import { useDashboard_ExpenseData } from "../../hooks/useDashboard_Data";
+import { useSelectedProject } from "../../slices/apiDataManager";
+import { DateRangePicker1 } from "../common/DateRangePicker";
+import { FormProvider, useForm } from "react-hook-form";
+import { localToUtc } from "../../utils/appUtils";
+
+const ExpenseChartDesign = () => {
+ const projectId = useSelectedProject();
+
+ const methods = useForm({
+ defaultValues: {
+ startDate: "",
+ endDate: "",
+ },
+ });
+
+ const { watch } = methods;
+
+ const [startDate, endDate] = watch(["startDate", "endDate"]);
+ console.log(startDate,endDate)
+ const { data, isLoading, isError, error, isFetching } = useDashboard_ExpenseData(
+ projectId,
+ localToUtc(startDate),
+ localToUtc(endDate)
+);
+
+ if (isError) return
{error.message}
;
+
+ const report = data?.report || [];
+
+ const labels = report.map((item) => item.projectName);
+ const series = report.map((item) => item.totalApprovedAmount || 0);
+ const total = data?.totalAmount || 0;
+
+ const donutOptions = {
+ chart: { type: "donut" },
+ labels,
+ legend: { show: false },
+ dataLabels: { enabled: true, formatter: (val) => `${val.toFixed(0)}%` },
+ colors: ["#7367F0", "#28C76F", "#FF9F43", "#EA5455", "#00CFE8", "#FF78B8"],
+ plotOptions: {
+ pie: {
+ donut: {
+ size: "70%",
+ labels: {
+ show: true,
+ total: {
+ show: true,
+ label: "Total",
+ fontSize: "16px",
+ formatter: () => `${total}`,
+ },
+ },
+ },
+ },
+ },
+ };
+
+
+ if (data?.report === 0) {
+ return
No data found
;
+ }
+
+ return (
+
+
+
+
Expense Breakdown
+
Detailed project expenses
+
+
+
+
+
+
+
+
+
+
+ {/* Initial loading: show full loader */}
+ {isLoading && (
+
+ Loading...
+
+ )}
+
+ {/* Data display */}
+ {!isLoading && report.length === 0 && (
+
No data found
+ )}
+
+ {!isLoading && report.length > 0 && (
+ <>
+ {/* Overlay spinner for refetch */}
+ {isFetching && (
+
+ Loading...
+
+ )}
+
+
+ item.totalApprovedAmount || 0)}
+ type="donut"
+ width="320"
+ />
+
+
+
+
+ {report.map((item, idx) => (
+
+
+
+
+
+
+
+ {item.projectName}
+ {item.totalApprovedAmount}
+
+
+ ))}
+
+
+ >
+ )}
+
+
+
+ );
+};
+
+export default ExpenseChartDesign;
diff --git a/src/components/Dashboard/ExpenseChartDesign2.jsx b/src/components/Dashboard/ExpenseChartDesign2.jsx
deleted file mode 100644
index e5df1bb2..00000000
--- a/src/components/Dashboard/ExpenseChartDesign2.jsx
+++ /dev/null
@@ -1,119 +0,0 @@
-import React, { useState } from "react";
-import Chart from "react-apexcharts";
-import DateRangePicker from "../common/DateRangePicker";
-import { useDashboard_ExpenseData } from "../../hooks/useDashboard_Data";
-import { useSelectedProject } from "../../slices/apiDataManager";
-
-const ExpenseChartDesign2 = () => {
- const projectId = useSelectedProject()
- const [dateRange, setDateRange] = useState({ startDate: "", endDate: "" });
-
- const { data, isLoading, isError, error } = useDashboard_ExpenseData(
- projectId,
- dateRange.startDate,
- dateRange.endDate
- );
-
- if (isLoading) return
Loading....
- if (isError) return
{error.message}
;
-
- const report = data?.report || [];
-
- // Map the API data to chart labels and series
- const labels = report.map((item) => item.projectName);
- const series = report.map((item) => item.totalApprovedAmount || 0);
- const total = data?.totalAmount || 0;
-
- const donutOptions = {
- chart: { type: "donut" },
- labels,
- legend: { show: false },
- dataLabels: { enabled: true, formatter: (val) => `${val.toFixed(0)}%` },
- colors: ["#7367F0", "#28C76F", "#FF9F43", "#EA5455", "#00CFE8", "#FF78B8"],
- plotOptions: {
- pie: {
- donut: {
- size: "70%",
- labels: {
- show: true,
- total: {
- show: true,
- label: "Total",
- fontSize: "16px",
- formatter: () => `${total}`,
- },
- },
- },
- },
- },
- };
-
- if (data?.report === 0) {
- return
- No data found
-
- }
-
- return (
-
-
-
-
Expense Breakdown
-
Detailed project expenses
-
-
-
-
-
-
-
- {report.length === 0 ? (
-
- No data found
-
- ) : (
- <>
-
- item.totalApprovedAmount || 0)}
- type="donut"
- width="320"
- />
-
-
-
-
- {report.map((item, idx) => (
-
-
-
-
-
-
-
- {item.projectName}
- {item.totalApprovedAmount}
-
-
- ))}
-
-
- >
- )}
-
-
- );
-};
-
-export default ExpenseChartDesign2;
diff --git a/src/components/Layout/Header.jsx b/src/components/Layout/Header.jsx
index ec55b48c..870672e3 100644
--- a/src/components/Layout/Header.jsx
+++ b/src/components/Layout/Header.jsx
@@ -67,7 +67,7 @@ const Header = () => {
if (projectLoading) return "Loading...";
if (!projectNames?.length) return "No Projects Assigned";
if (projectNames.length === 1) return projectNames[0].name;
-
+ if (selectedProject === null) return "All Projects";
const selectedObj = projectNames.find((p) => p.id === selectedProject);
return selectedObj
? selectedObj.name
@@ -199,6 +199,14 @@ const Header = () => {
className="dropdown-menu"
style={{ overflow: "auto", maxHeight: "300px" }}
>
+
+
+ handleProjectChange(null)}
+ >All Project
+
+
{[...projectsForDropdown]
.sort((a, b) => a?.name?.localeCompare(b.name))
.map((project) => (
diff --git a/src/components/common/DateRangePicker.jsx b/src/components/common/DateRangePicker.jsx
index 72aad155..99fae06f 100644
--- a/src/components/common/DateRangePicker.jsx
+++ b/src/components/common/DateRangePicker.jsx
@@ -14,7 +14,6 @@ const DateRangePicker = ({
if (endDateMode === "yesterday") {
endDate.setDate(endDate.getDate() - 1);
}
-
endDate.setHours(0, 0, 0, 0);
const startDate = new Date(endDate);
@@ -30,9 +29,14 @@ const DateRangePicker = ({
static: true,
clickOpens: true,
maxDate: endDate,
- onChange: (selectedDates, dateStr) => {
- const [startDateString, endDateString] = dateStr.split(" to ");
- onRangeChange?.({ startDate: startDateString, endDate: endDateString });
+ onChange: (selectedDates) => {
+ if (selectedDates.length === 2) {
+ const [start, end] = selectedDates;
+ onRangeChange?.({
+ startDate: start.toLocaleDateString("en-CA"),
+ endDate: end.toLocaleDateString("en-CA"),
+ });
+ }
},
});
@@ -47,9 +51,7 @@ const DateRangePicker = ({
}, [onRangeChange, DateDifference, endDateMode]);
const handleIconClick = () => {
- if (inputRef.current) {
- inputRef.current._flatpickr.open(); // directly opens flatpickr
- }
+ inputRef.current?._flatpickr?.open();
};
return (
@@ -61,9 +63,9 @@ const DateRangePicker = ({
id="flatpickr-range"
ref={inputRef}
/>
-
@@ -72,10 +74,6 @@ const DateRangePicker = ({
export default DateRangePicker;
-
-
-
-
export const DateRangePicker1 = ({
startField = "startDate",
endField = "endDate",
@@ -85,6 +83,8 @@ export const DateRangePicker1 = ({
resetSignal,
defaultRange = true,
maxDate = null,
+ sm,
+ md,
...rest
}) => {
const inputRef = useRef(null);
@@ -118,7 +118,7 @@ export const DateRangePicker1 = ({
mode: "range",
dateFormat: "d-m-Y",
allowInput: allowText,
- maxDate ,
+ maxDate,
onChange: (selectedDates) => {
if (selectedDates.length === 2) {
const [start, end] = selectedDates;
@@ -148,31 +148,31 @@ export const DateRangePicker1 = ({
}, []);
useEffect(() => {
- if (resetSignal !== undefined) {
- if (defaultRange) {
- applyDefaultDates();
- } else {
- setValue(startField, "", { shouldValidate: true });
- setValue(endField, "", { shouldValidate: true });
+ if (resetSignal !== undefined) {
+ if (defaultRange) {
+ applyDefaultDates();
+ } else {
+ setValue(startField, "", { shouldValidate: true });
+ setValue(endField, "", { shouldValidate: true });
- if (inputRef.current?._flatpickr) {
- inputRef.current._flatpickr.clear();
+ if (inputRef.current?._flatpickr) {
+ inputRef.current._flatpickr.clear();
+ }
}
}
- }
-}, [resetSignal, defaultRange, setValue, startField, endField]);
-
+ }, [resetSignal, defaultRange, setValue, startField, endField]);
const start = getValues(startField);
const end = getValues(endField);
const formattedValue = start && end ? `${start} To ${end}` : "";
return (
-
+
{
inputRef.current = el;
@@ -181,13 +181,10 @@ export const DateRangePicker1 = ({
readOnly={!allowText}
autoComplete="off"
/>
- inputRef.current?._flatpickr?.open()}
- >
-
-
+ >
);
};
-
diff --git a/src/hooks/useDashboard_Data.jsx b/src/hooks/useDashboard_Data.jsx
index a65320e0..74731695 100644
--- a/src/hooks/useDashboard_Data.jsx
+++ b/src/hooks/useDashboard_Data.jsx
@@ -212,12 +212,19 @@ export const useDashboard_AttendanceData = (date, projectId) => {
}
export const useDashboard_ExpenseData = (projectId, startDate, endDate) => {
+ const hasBothDates = !!startDate && !!endDate;
+ const noDatesSelected = !startDate && !endDate;
+
+ const shouldFetch =
+ noDatesSelected ||
+ hasBothDates;
return useQuery({
queryKey: ["dashboardExpenses", projectId, startDate, endDate],
queryFn: async () => {
const resp = await GlobalRepository.getExpenseData(projectId, startDate, endDate);
- return resp.data; // this will return the "data" object from API response
+ return resp.data;
},
+ enabled:shouldFetch
});
};
@@ -242,16 +249,17 @@ export const useDashboardTasksCardData = (projectId) => {
}
})
}
-// export const useAttendanceOverviewData = (projectId, days) => {
-// return useQuery({
-// queryKey:["dashboardAttendanceOverView",projectId],
-// queryFn:async()=> {
+export const useAttendanceOverviewData = (projectId, days) => {
+ return useQuery({
+ queryKey: ["dashboardAttendanceOverView", projectId, days],
+ queryFn: async () => {
+ const resp = await GlobalRepository.getAttendanceOverview(projectId, days);
+ return resp.data;
+ },
+ enabled: !!projectId,
+ });
+};
-// const resp = await GlobalRepository.getAttendanceOverview(projectId, days);
-// return resp.data;
-// }
-// })
-// }
export const useDashboardProjectsCardData = () => {
return useQuery({
diff --git a/src/utils/appUtils.js b/src/utils/appUtils.js
index 0766514a..5f117ce6 100644
--- a/src/utils/appUtils.js
+++ b/src/utils/appUtils.js
@@ -72,11 +72,11 @@ export const normalizeAllowedContentTypes = (allowedContentType) => {
export function localToUtc(localDateString) {
if (!localDateString || typeof localDateString !== "string") return null;
-
- const [year, month, day] = localDateString.trim().split("-");
- if (!year || !month || !day) return null;
+ const [day, month, year] = localDateString.trim().split("-");
+ if (!day || !month || !year) return null;
+ // Create date in UTC
const date = new Date(Date.UTC(Number(year), Number(month) - 1, Number(day), 0, 0, 0));
return isNaN(date.getTime()) ? null : date.toISOString();
-}
\ No newline at end of file
+}