diff --git a/src/components/BMDashboard/WeeklyProjectSummary/CostPredictionChart.jsx b/src/components/BMDashboard/WeeklyProjectSummary/CostPredictionChart.jsx
index e66b940f30..de7189b90d 100644
--- a/src/components/BMDashboard/WeeklyProjectSummary/CostPredictionChart.jsx
+++ b/src/components/BMDashboard/WeeklyProjectSummary/CostPredictionChart.jsx
@@ -12,6 +12,7 @@ import {
ReferenceLine,
} from 'recharts';
import styles from './CostPredictionChart.module.css';
+import { fetchBMProjects } from '../../../actions/bmdashboard/projectActions';
import projectCostService from '../../../services/projectCostService';
// Custom dot renderer (unchanged)
@@ -63,18 +64,50 @@ function renderDotTopOrBottom(lineKey, color) {
return null;
};
}
+function CustomTooltip({ active, payload, label }) {
+ if (!active || !payload || payload.length === 0) return null;
+ return (
+
+
{label}
+ {payload.map(item => (
+
+ {item.name}: $
+ {Number(item.value).toLocaleString()}
+
+ ))}
+
+ );
+}
function CostPredictionChart({ projectId }) {
const dispatch = useDispatch();
const [chartData, setChartData] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
+ // Date filters
+ const [startDate, setStartDate] = useState('');
+ const [endDate, setEndDate] = useState('');
const darkMode = useSelector(state => state.theme.darkMode);
+ //Project list for dropdown
+ const projects = useSelector(state => state.bmProjects) || [];
+ const [selectedProject, setSelectedProject] = useState('');
const legendItems = [
{ label: 'Planned Cost', color: '#7acba6', type: 'circle' },
{ label: 'Actual Cost', color: '#9aa6ff', type: 'circle' },
{ label: 'Predicted Cost', color: '#ff8c2a', type: 'dash' },
];
+ // Reset all the filters
+ const resetFilters = () => {
+ setSelectedProject('');
+ setStartDate('');
+ setEndDate('');
+ setError('');
+ };
+ //Project dropdown
+ useEffect(() => {
+ dispatch(fetchBMProjects());
+ }, [dispatch]);
+
useEffect(() => {
const fetchData = async () => {
try {
@@ -106,8 +139,9 @@ function CostPredictionChart({ projectId }) {
}
};
- if (projectId) fetchData();
- }, [projectId]);
+ const effectiveProjectId = selectedProject || projectId; //fetches data when either the prop projectId or the dropdown selection changes
+ if (effectiveProjectId) fetchData();
+ }, [projectId, selectedProject]);
if (loading) return Loading chart data...
;
if (error) return Error: {error}
;
@@ -117,16 +151,74 @@ function CostPredictionChart({ projectId }) {
year: 'numeric',
});
+ // Filter data by date range
+ const filteredData = chartData.filter(item => {
+ const itemDate = new Date(item.month);
+ const start = startDate ? new Date(startDate) : null;
+ const end = endDate ? new Date(endDate) : null;
+ return (!start || itemDate >= start) && (!end || itemDate <= end);
+ });
+
// THEME COLORS — only for grid, axis ticks/lines, legend
const gridColor = darkMode ? '#e5e7eb' : '#9ca3af'; // grid lines
const tickColor = darkMode ? '#e5e7eb' : '#9ca3af'; // tick text
const axisLineCol = darkMode ? '#e5e7eb' : '#9ca3af'; // axis baseline & tick marks
const legendColor = darkMode ? '#e5e7eb' : '#9ca3af'; // legend text
+
return (
Planned Vs Actual costs tracking
+ {/* Project Filter Dropdown */}
+
+
+
+
+
+
+
+ {/* Date Filters */}
+
+ {/* Reset Filters button */}
+
+
+
-
+
{/* Grid */}
(
-
- {payload.value}
-
- )}
- tickMargin={0} // apply margin at XAxis level, not inside
+ tick={({ x, y, payload }) => {
+ // Converts "February 2024" to "Feb 24"
+ const shortLabel = payload.value.replace(
+ /(\w{3})\w*\s(\d{4})/,
+ (_, m, y) => `${m} ${y.slice(-2)}`,
+ );
+
+ return (
+
+ {shortLabel}
+
+ );
+ }}
+ tickMargin={10}
/>
+
(
@@ -159,7 +261,11 @@ function CostPredictionChart({ projectId }) {
)}
/>
{/* Tooltip & Legend */}
-
+ }
+ labelFormatter={label => ` ${label}`}
+ formatter={(value, name) => [`$${Number(value).toLocaleString()}`, name]}
+ />