diff --git a/src/components/BMDashboard/WeeklyProjectSummary/ProjectRiskProfileOverview.jsx b/src/components/BMDashboard/WeeklyProjectSummary/ProjectRiskProfileOverview.jsx
index 1effa1946b..0626ba1633 100644
--- a/src/components/BMDashboard/WeeklyProjectSummary/ProjectRiskProfileOverview.jsx
+++ b/src/components/BMDashboard/WeeklyProjectSummary/ProjectRiskProfileOverview.jsx
@@ -1,5 +1,4 @@
import { useState, useEffect, useRef } from 'react';
-import { useSelector } from 'react-redux';
import {
BarChart,
Bar,
@@ -12,12 +11,10 @@ import {
} from 'recharts';
import Select from 'react-select';
import httpService from '../../../services/httpService';
+import { useSelector } from 'react-redux';
import styles from './ProjectRiskProfileOverview.module.css';
-// Fetch project risk profile data from backend
-
export default function ProjectRiskProfileOverview() {
- const darkMode = useSelector(state => state.theme?.darkMode || false);
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
@@ -27,25 +24,23 @@ export default function ProjectRiskProfileOverview() {
const [allDates, setAllDates] = useState([]);
const [selectedDates, setSelectedDates] = useState([]);
const [showDateDropdown, setShowDateDropdown] = useState(false);
+ const darkMode = useSelector(state => state.theme.darkMode);
- // Refs for focusing dropdowns
const projectWrapperRef = useRef(null);
const dateWrapperRef = useRef(null);
useEffect(() => {
- function handleClickOutside(event) {
+ const handleClickOutside = event => {
if (projectWrapperRef.current && !projectWrapperRef.current.contains(event.target)) {
setShowProjectDropdown(false);
}
if (dateWrapperRef.current && !dateWrapperRef.current.contains(event.target)) {
setShowDateDropdown(false);
}
- }
+ };
document.addEventListener('mousedown', handleClickOutside);
- return () => {
- document.removeEventListener('mousedown', handleClickOutside);
- };
+ return () => document.removeEventListener('mousedown', handleClickOutside);
}, []);
useEffect(() => {
@@ -61,7 +56,6 @@ export default function ProjectRiskProfileOverview() {
setData(result);
setAllProjects(result.map(p => p.projectName));
setSelectedProjects(result.map(p => p.projectName));
- // Extract all unique dates from all projects
const dates = Array.from(new Set(result.flatMap(p => p.dates || [])));
setAllDates(dates);
setSelectedDates(dates);
@@ -74,263 +68,262 @@ export default function ProjectRiskProfileOverview() {
fetchData();
}, []);
- // Filter projects that are ongoing on ALL selected dates and in selectedProjects
const filteredData = data.filter(
p =>
(selectedProjects.length === 0 || selectedProjects.includes(p.projectName)) &&
(selectedDates.length === 0 || (p.dates || []).some(d => selectedDates.includes(d))),
);
- // Project label function
const getProjectLabel = () => {
if (selectedProjects.length === allProjects.length) return 'ALL';
if (selectedProjects.length === 0) return 'Select projects';
return `${selectedProjects.length} selected`;
};
- // Dates label function
const getDateLabel = () => {
if (selectedDates.length === allDates.length) return 'ALL';
if (selectedDates.length === 0) return 'Select dates';
return `${selectedDates.length} selected`;
};
- const getOptionBackgroundColor = isFocused => {
- if (isFocused) {
- return darkMode ? '#3a506b' : '#f0f0f0';
- }
- return darkMode ? '#1c2541' : '#ffffff';
+ const chartTheme = {
+ grid: darkMode ? '#3f4652' : '#e8e8e8',
+ axisText: darkMode ? '#d7dbe2' : '#666',
+ axisLine: darkMode ? '#6b7280' : '#d5d5d5',
+ tooltipBg: darkMode ? '#1f2937' : '#fff',
+ tooltipBorder: darkMode ? '#4b5563' : '#e0e0e0',
+ tooltipText: darkMode ? '#f3f4f6' : '#333',
+ hover: darkMode ? 'rgba(66, 133, 244, 0.16)' : 'rgba(66, 133, 244, 0.08)',
};
const customSelectStyles = {
control: base => ({
...base,
- fontSize: 14,
- minHeight: 22,
- width: 120,
- background: 'none',
- border: 'none',
+ fontSize: 12,
+ minHeight: 34,
+ backgroundColor: darkMode ? '#2c2c2c' : '#fff',
+ borderColor: darkMode ? '#555' : '#d5d5d5',
boxShadow: 'none',
- textAlign: 'center',
- alignItems: 'center',
- padding: 0,
}),
valueContainer: base => ({
...base,
- padding: '0 2px',
- justifyContent: 'center',
+ padding: '2px 6px',
}),
multiValue: base => ({
...base,
- background: darkMode ? '#3a506b' : '#e6f7ff',
- fontSize: 12,
- margin: '0 2px',
+ background: darkMode ? '#444' : '#e8f0fe',
+ fontSize: 11,
}),
multiValueLabel: base => ({
...base,
- color: darkMode ? '#ffffff' : '#000000',
+ color: darkMode ? '#eee' : '#333',
}),
multiValueRemove: base => ({
...base,
- color: darkMode ? '#ffffff' : '#000000',
+ color: darkMode ? '#eee' : '#333',
':hover': {
- backgroundColor: darkMode ? '#2f4157' : '#bae7ff',
- color: darkMode ? '#ffffff' : '#000000',
+ backgroundColor: darkMode ? '#555' : '#dbe7ff',
+ color: darkMode ? '#fff' : '#111',
},
}),
input: base => ({
...base,
- margin: 0,
- padding: 0,
- textAlign: 'center',
- color: darkMode ? '#ffffff' : '#000000',
+ color: darkMode ? '#eee' : '#333',
}),
placeholder: base => ({
...base,
- color: '#aaa',
- textAlign: 'center',
- }),
- dropdownIndicator: base => ({
- ...base,
- padding: 0,
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'center',
+ color: darkMode ? '#c7c7c7' : '#666',
}),
menu: base => ({
...base,
zIndex: 9999,
- fontSize: 14,
- background: darkMode ? '#1c2541' : '#ffffff',
+ backgroundColor: darkMode ? '#2c2c2c' : '#fff',
+ border: darkMode ? '1px solid #555' : '1px solid #e2e2e2',
+ boxShadow: darkMode ? '0 4px 16px rgba(0, 0, 0, 0.45)' : '0 4px 16px rgba(0,0,0,0.12)',
}),
option: (base, state) => ({
...base,
- backgroundColor: getOptionBackgroundColor(state.isFocused),
- color: darkMode ? '#ffffff' : '#000000',
- fontWeight: state.isFocused ? 'bold' : 'normal',
- '&:active': {
- backgroundColor: darkMode ? '#2f4157' : '#e6f7ff',
- },
+ color: darkMode ? '#eee' : '#333',
+ backgroundColor: state.isSelected
+ ? darkMode
+ ? '#4a4a4a'
+ : '#dbe7ff'
+ : state.isFocused
+ ? darkMode
+ ? '#3a3a3a'
+ : '#f5f5f5'
+ : darkMode
+ ? '#2c2c2c'
+ : '#fff',
}),
};
- // Colors aligned with your global theme
- const chartColors = {
- grid: darkMode ? 'rgba(255,255,255,0.1)' : '#e5e5e5',
- text: darkMode ? '#e5e5e5' : '#333',
- tooltipBg: darkMode ? '#1c2541' : '#ffffff',
- tooltipBorder: darkMode ? '#3a506b' : '#ccc',
- tooltipText: darkMode ? '#ffffff' : '#000000',
- };
-
- if (loading) return
Loading project risk profiles...
;
- if (error) return {error}
;
+ if (loading)
+ return (
+
+
Loading project risk profiles...
+
+ );
+ if (error)
+ return (
+
+ );
return (
-
-
Project Risk Profile Overview
-
- {/* Project Dropdown */}
-
-
Project
-
-
- {/* Date Dropdown */}
-
-
Dates
-
+
+
+
+
Overall Risk Profile
+
+
+ {/* Project Dropdown */}
+
+
Project
+
+ {showProjectDropdown && (
+
+
+ )}
+
+
+ {/* Date Dropdown */}
+
+
Dates
+
+ {showDateDropdown && (
+
+
+ )}
+
+
-
- {/* Chart Section */}
-
-
- {
- return {
- ...item,
- predictedCostOverrun: item.predictedCostOverrun,
- };
- })}
- margin={{ top: 20, right: 40, left: 60, bottom: 80 }}
- barCategoryGap="20%"
- barGap={4}
- >
-
-
- (Number.isInteger(value) ? value : value.toFixed(0))}
- tick={{ fontSize: 12, fill: chartColors.text }}
- />
- {
- if (typeof value === 'number') {
- // Format Time Delay specifically to 2 decimal places
- if (name === 'Predicted Time Delay (%)') {
- return value.toFixed(2);
- }
- // For other values, use 2 decimal places if not integer
- return Number.isInteger(value) ? value.toString() : value.toFixed(2);
- }
- return value;
- }}
- />
-
-
-
-
-
-
+
+
+
+
+ Predicted Cost Overrun Percentage
+
+
+
+ Issues
+
+
+
+ Predicted Time Delay Percentage
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {filteredData.length === 0 && (
+
No risk profile data for selected filters.
+ )}
+
);
diff --git a/src/components/BMDashboard/WeeklyProjectSummary/ProjectRiskProfileOverview.module.css b/src/components/BMDashboard/WeeklyProjectSummary/ProjectRiskProfileOverview.module.css
index 85f5697447..554eb87b27 100644
--- a/src/components/BMDashboard/WeeklyProjectSummary/ProjectRiskProfileOverview.module.css
+++ b/src/components/BMDashboard/WeeklyProjectSummary/ProjectRiskProfileOverview.module.css
@@ -1,90 +1,320 @@
-.chartCard {
- background-color: #ffffff;
- color: #232323;
- border-radius: 8px;
- box-shadow: 0 2px 8px #eee;
- padding: 24px;
- margin-bottom: 24px;
+.wrapper {
+ width: 87vw;
+ display: block;
+ box-sizing: border-box;
+ padding: 0;
+ overflow-x: auto;
+ margin: 0 auto;
+ transition: background-color 0.25s ease;
+}
+
+.darkMode.wrapper {
+ background: #141a23;
+}
+
+.container {
width: 100%;
- grid-column: 1 / -1;
- transition: background-color 0.3s ease, color 0.3s ease;
+ max-width: 1400px;
+ background: #fff;
+ border-radius: 10px;
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
+ padding: 36px;
+ box-sizing: border-box;
+ position: relative;
+ transition: background-color 0.25s ease, color 0.25s ease, border-color 0.25s ease;
}
-.chartCard.darkMode {
- background-color: #1b2a41; /* --color-oxford-blue */
- color: #e5e5e5; /* --text-dark */
- box-shadow: 2px 2px 4px 1px black; /* box-shadow-dark */
+.statusCard {
+ width: 87vw;
+ margin: 0 auto;
+ border-radius: 10px;
+ background: #fff;
+ border: 1px solid #e5e7eb;
+ box-shadow: 0 2px 12px rgb(0 0 0 / 8%);
+ padding: 24px;
}
-.chartTitle {
- margin-bottom: 24px;
- font-size: 24px; /* match previous standard or h2 size */
- font-weight: bold;
+.statusCard.darkMode {
+ background: #1e1e1e;
+ border-color: #374151;
+ color: #f3f4f6;
+ box-shadow: 0 2px 8px #111;
}
-.darkMode .chartTitle {
- color: inherit;
+.heading {
+ margin: 0;
+ padding: 0;
+ font-size: 28px;
+ font-weight: 700;
+ color: #1a1a1a;
+ letter-spacing: -0.3px;
}
-.filterContainer {
+.headerRow {
display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 36px;
gap: 40px;
flex-wrap: wrap;
- margin-bottom: 24px;
- align-items: flex-end;
}
-.formGroup {
+.darkMode .headerRow {
+ border-bottom-color: transparent;
+}
+
+.filterRow {
+ display: flex;
+ gap: 48px;
+ flex-wrap: nowrap;
+ align-items: center;
+ padding: 0;
+ margin-bottom: 0;
+ border-bottom: none;
+ justify-content: flex-end;
+ width: auto;
+ margin-left: auto;
+}
+
+.darkMode .filterRow {
+ border-bottom-color: transparent;
+}
+
+.dropdownWrapper {
display: flex;
flex-direction: column;
align-items: center;
- min-width: 90px;
+ min-width: 120px;
+ position: relative;
+ gap: 4px;
+ width: auto;
}
-.label {
- font-weight: bold;
- font-size: 16px;
+.dropdownLabel {
+ font-weight: 700;
+ font-size: 12px;
margin-bottom: 0;
+ color: #333;
+ display: block;
+ text-transform: capitalize;
+ line-height: 1.2;
+ letter-spacing: 0.3px;
+}
+
+.darkMode .dropdownLabel {
+ color: #f5f5f5;
}
.dropdownButton {
- font-size: 14px;
- color: #444;
- font-weight: 500;
- margin-bottom: 2px;
- cursor: pointer;
- position: relative;
- display: inline-block;
- min-width: 60px;
+ font-size: 12px;
+ font-weight: 600;
+ color: #555;
+ min-width: 90px;
text-align: center;
- background: none;
- border: none;
- padding: 0;
+ cursor: pointer;
+ background: #fff;
+ border: 1.5px solid #d5d5d5;
+ border-radius: 5px;
+ padding: 7px 12px;
+ transition: all 0.25s ease;
+ line-height: 1.2;
+}
+
+.dropdownButton:hover {
+ background: #f8f8f8;
+ border-color: #b0b0b0;
}
.darkMode .dropdownButton {
- color: #e5e5e5;
+ color: #ddd;
+ background: #333;
+ border-color: #555;
+}
+
+.darkMode .dropdownButton:hover {
+ background: #404040;
+ border-color: #777;
}
.dropdownMenu {
position: absolute;
- left: 0;
top: 100%;
+ left: 50%;
+ transform: translateX(-50%);
+ width: 200px;
z-index: 2000;
- min-width: 120px;
- background: white;
- box-shadow: 0 2px 8px #eee;
- border-radius: 4px;
- margin-top: 2px;
+ margin-top: 8px;
+ border-radius: 6px;
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
+ background: #fff;
+ padding: 0;
}
.darkMode .dropdownMenu {
- background-color: #1c2541; /* --color-space-cadet */
- box-shadow: 2px 2px 4px 1px black;
+ background: #2c2c2c;
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
+}
+
+/* React-select overrides */
+.customSelect__control {
+ font-size: 12px;
+ min-height: auto;
+ background: transparent;
+ border: none;
+ box-shadow: none;
+ padding: 0;
+ cursor: pointer;
}
-.chartContainer {
+.customSelect__control:focus-within {
+ box-shadow: none;
+}
+
+.darkMode .customSelect__control {
+ color: #ddd;
+ background: transparent;
+}
+
+.customSelect__multi-value {
+ background: #e8f0fe;
+ font-size: 11px;
+ border-radius: 3px;
+ padding: 2px 6px;
+ margin: 2px;
+}
+
+.darkMode .customSelect__multi-value {
+ background: #444;
+ color: #ddd;
+}
+
+.customSelect__option {
+ color: #333;
+ background-color: #fff;
+ font-size: 12px;
+ padding: 8px 12px;
+}
+
+.customSelect__option:hover {
+ background-color: #f5f5f5;
+}
+
+.darkMode .customSelect__option {
+ color: #ddd;
+ background-color: #2c2c2c;
+}
+
+.darkMode .customSelect__option:hover {
+ background-color: #3a3a3a;
+}
+
+.customSelect__menu {
+ z-index: 9999;
+ background: #fff;
+ border-radius: 6px;
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
+}
+
+.darkMode .customSelect__menu {
+ background: #2c2c2c;
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
+}
+
+.chartWrapper {
width: 100%;
- margin: 0 -24px;
- padding: 0 24px;
+ height: 520px;
+ margin-top: 32px;
+ padding: 24px 28px 28px 28px;
+ background: #fafafa;
+ border-radius: 10px;
+ border: 1.5px solid #e8e8e8;
+ box-sizing: border-box;
+ display: flex;
+ flex-direction: column;
+ position: relative;
+ transition: background-color 0.25s ease, border-color 0.25s ease;
+}
+
+.darkMode .chartWrapper {
+ background: #252525;
+ border-color: #404040;
+}
+
+.legendWrapper {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ gap: 40px;
+ padding-bottom: 20px;
+ margin-bottom: 20px;
+}
+
+.darkMode .legendWrapper {
+ border-bottom-color: transparent;
+}
+
+.legendItem {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ font-size: 12px;
+ font-weight: 500;
+ color: #555;
+}
+
+.darkMode .legendItem {
+ color: #ccc;
+}
+
+.legendSquare {
+ width: 14px;
+ height: 14px;
+ border-radius: 2px;
+ flex-shrink: 0;
+}
+
+.error {
+ color: #dc2626;
+ font-size: 15px;
+ font-weight: 500;
+}
+
+.statusCard.darkMode .error {
+ color: #fca5a5;
+}
+
+.loading {
+ font-size: 15px;
+ font-weight: 500;
+ color: #374151;
+}
+
+.statusCard.darkMode .loading {
+ color: #d1d5db;
+}
+
+.emptyState {
+ text-align: center;
+ margin-top: 16px;
+ padding: 10px;
+ border-radius: 6px;
+ font-size: 13px;
+ color: #6b7280;
+ background: #f3f4f6;
+}
+
+.darkMode .emptyState {
+ color: #d1d5db;
+ background: #374151;
+}
+
+/* ===================== DARK MODE ===================== */
+.darkMode .container {
+ background: #1e1e1e;
+ box-shadow: 0 2px 8px #111;
+ color: #eee;
+}
+
+.darkMode .heading {
+ color: #fff;
}
diff --git a/src/components/BMDashboard/WeeklyProjectSummary/WeeklyProjectSummary.jsx b/src/components/BMDashboard/WeeklyProjectSummary/WeeklyProjectSummary.jsx
index 652de05d16..7cc341915e 100644
--- a/src/components/BMDashboard/WeeklyProjectSummary/WeeklyProjectSummary.jsx
+++ b/src/components/BMDashboard/WeeklyProjectSummary/WeeklyProjectSummary.jsx
@@ -583,7 +583,9 @@ function WeeklyProjectSummary() {
return (