diff --git a/src/components/BMDashboard/BMDashboard.jsx b/src/components/BMDashboard/BMDashboard.jsx
index ae8a7cff40..5ff0c9a1d9 100644
--- a/src/components/BMDashboard/BMDashboard.jsx
+++ b/src/components/BMDashboard/BMDashboard.jsx
@@ -201,7 +201,7 @@ export function BMDashboard() {
) : (
<>
-
+ {/* */}
>
)}
diff --git a/src/components/BMDashboard/ProjectStatus/ProjectStatusDonutChart.jsx b/src/components/BMDashboard/ProjectStatus/ProjectStatusDonutChart.jsx
index 661255dab9..d38d92830e 100644
--- a/src/components/BMDashboard/ProjectStatus/ProjectStatusDonutChart.jsx
+++ b/src/components/BMDashboard/ProjectStatus/ProjectStatusDonutChart.jsx
@@ -1,11 +1,13 @@
import React, { useEffect, useState } from 'react';
+import { useSelector } from 'react-redux';
import { PieChart, Pie, Cell, Tooltip, Legend, ResponsiveContainer, Label } from 'recharts';
import axios from 'axios';
import styles from './ProjectStatusDonutChart.module.css';
-const COLORS = ['#B39DDB', '#80DEEA', '#FFABAB']; // Active, Completed, Delayed
+const COLORS = ['#B39DDB', '#80DEEA', '#FFABAB'];
export default function ProjectStatusDonutChart() {
+ const darkMode = useSelector(state => state.theme?.darkMode || false);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [statusData, setStatusData] = useState(null);
@@ -18,31 +20,19 @@ export default function ProjectStatusDonutChart() {
setLoading(true);
setError(null);
- // Build query string
const query = [];
if (startDate) query.push(`startDate=${startDate}`);
if (endDate) query.push(`endDate=${endDate}`);
const queryString = query.length ? `?${query.join('&')}` : '';
- // Get token from localStorage (Dev Admin session)
const token = localStorage.getItem('token');
const res = await axios.get(`http://localhost:4500/api/projects/status${queryString}`, {
headers: { Authorization: token },
});
- // TEMPORARY MOCK DATA - for testing purposes
- /*setStatusData({
- totalProjects: 50,
- activeProjects: 20,
- completedProjects: 20,
- delayedProjects: 10,
- });
- return;*/
-
setStatusData(res.data);
} catch (err) {
- // console.error(err);
setError('Unable to load project status.');
} finally {
setLoading(false);
@@ -63,10 +53,9 @@ export default function ProjectStatusDonutChart() {
{ name: 'Delayed Projects', value: statusData.delayedProjects },
];
- // SHOW MESSAGE WHEN THERE IS NO DATA
if (pieData.every(item => item.value === 0)) {
return (
-
+
PROJECT STATUS
No project status data available.
@@ -84,7 +73,7 @@ export default function ProjectStatusDonutChart() {
!statusData.activeProjects && !statusData.completedProjects && !statusData.delayedProjects;
return (
-
+
PROJECT STATUS
@@ -108,9 +97,8 @@ export default function ProjectStatusDonutChart() {
- {/* Only draw the ring if at least one status has data */}
{!allZero && (
-
+
-
+
diff --git a/src/components/BMDashboard/ProjectStatus/ProjectStatusDonutChart.module.css b/src/components/BMDashboard/ProjectStatus/ProjectStatusDonutChart.module.css
index 0d9e347cf3..a40a8103de 100644
--- a/src/components/BMDashboard/ProjectStatus/ProjectStatusDonutChart.module.css
+++ b/src/components/BMDashboard/ProjectStatus/ProjectStatusDonutChart.module.css
@@ -7,6 +7,7 @@
border-radius: 12px;
position: relative;
border: 1px solid rgba(0, 0, 0, 0.12);
+ transition: background-color 0.3s, color 0.3s;
}
.title {
@@ -78,6 +79,7 @@
text-align: center;
}
}
+
.centerLabel {
font-size: 16px;
font-weight: 600;
@@ -94,4 +96,29 @@
text-align: center;
margin-top: 16px;
font-weight: 500;
+}
+
+.darkContainer {
+ background-color: #1b2a41 !important;
+ color: #ffffff !important;
+ border-color: #3a506b !important;
+}
+
+.darkContainer input[type="date"] {
+ background-color: #2a3f5f !important;
+ color: #ffffff !important;
+ border: 1px solid #3a506b !important;
+ color-scheme: dark;
+ padding: 4px 8px;
+ border-radius: 4px;
+}
+
+.darkContainer .label {
+ color: #b5bac5 !important;
+}
+
+.darkContainer .title,
+.darkContainer h3,
+.darkContainer .noDataMessage {
+ color: #ffffff !important;
}
\ No newline at end of file
diff --git a/src/components/BMDashboard/Projects/ProjectsList.jsx b/src/components/BMDashboard/Projects/ProjectsList.jsx
index 9d5e408610..ba59a1694b 100644
--- a/src/components/BMDashboard/Projects/ProjectsList.jsx
+++ b/src/components/BMDashboard/Projects/ProjectsList.jsx
@@ -1,6 +1,6 @@
-import { useState } from 'react';
+import { useState, useEffect, useRef } from 'react';
import { useSelector } from 'react-redux';
-import { Row, Col } from 'reactstrap';
+import { Row, Col, FormGroup, Label, Spinner } from 'reactstrap';
import Select from 'react-select';
import ProjectSummary from './ProjectSummary';
import styles from '../BMDashboard.module.css';
@@ -8,21 +8,36 @@ import styles from '../BMDashboard.module.css';
function ProjectsList() {
const projects = useSelector(state => state.bmProjects) || [];
const darkMode = useSelector(state => state.theme?.darkMode || false);
+
const [selectedProjects, setSelectedProjects] = useState([]);
+ const [isUpdating, setIsUpdating] = useState(false);
+
+ const timeoutRef = useRef(null);
+
+ useEffect(() => {
+ return () => {
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
+ };
+ }, []);
+
const projectOptions = projects.map(project => ({
value: project._id,
label: project.name,
}));
const handleSelectChange = selectedOptions => {
- setSelectedProjects(selectedOptions || []);
+ setIsUpdating(true);
+
+ timeoutRef.current = setTimeout(() => {
+ setSelectedProjects(selectedOptions || []);
+ setIsUpdating(false);
+ }, 600);
};
const filteredProjects = selectedProjects.length
? projects.filter(project => selectedProjects.some(selected => selected.value === project._id))
: projects;
- // Custom styles for react-select in dark mode
const selectStyles = {
control: (base, state) => ({
...base,
@@ -105,34 +120,78 @@ function ProjectsList() {
className="ml-0 text-center mt-5"
style={{ width: '100%', display: 'flex', justifyContent: 'center', flexDirection: 'column' }}
>
-
-
+
+
+
+
+
+
+
+ Select one or multiple projects from the dropdown to filter the inventory and building
+ data below.
+
+
+
+
+
+ {selectedProjects.length > 0
+ ? `Showing Summary for: ${selectedProjects.map(p => p.label).join(', ')}`
+ : 'Showing All Projects'}
+
+ {isUpdating && (
+
+ )}
+
+
{filteredProjects.length ? (
{filteredProjects.map(project => (
-
))}
) : (
- No projects data
+
+ No projects data available for the selected filters.
+
)}