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. +

)}