diff --git a/src/components/MaterialSummary/MaterialSummary.jsx b/src/components/MaterialSummary/MaterialSummary.jsx index e28a0a43ba..cf537fa779 100644 --- a/src/components/MaterialSummary/MaterialSummary.jsx +++ b/src/components/MaterialSummary/MaterialSummary.jsx @@ -1,9 +1,10 @@ -import { useState, useEffect } from 'react'; +import { useState, useEffect, useRef } from 'react'; import { Chart as ChartJS, ArcElement, Tooltip, Legend } from 'chart.js'; import { Pie } from 'react-chartjs-2'; import { mockProjects, mockMaterialData, chartColors } from './Data'; import styles from './MaterialSummary.module.css'; import { useSelector } from 'react-redux'; +import Header from '../Header'; // Register ChartJS components ChartJS.register(ArcElement, Tooltip, Legend); @@ -15,8 +16,17 @@ export default function MaterialUsageDashboard() { const [chartData, setChartData] = useState(null); const [loading, setLoading] = useState(false); const [increasePercentage, setIncreasePercentage] = useState(0); + const [chartKey, setChartKey] = useState(0); + const chartRef = useRef(null); - const darkMode = useSelector(state => state.theme.darkMode); + // Get darkMode with multiple fallbacks + const themeState = useSelector(state => state?.theme); + const darkMode = themeState?.darkMode ?? false; + + // Trigger chart re-render when darkMode changes + useEffect(() => { + setChartKey(prev => prev + 1); + }, [darkMode]); // Update the updateChartData function to handle the new material types with appropriate colors const updateChartData = () => { @@ -95,245 +105,218 @@ export default function MaterialUsageDashboard() { }, 800); }, [selectedProject, selectedMaterial, showIncreaseOnly]); - // Function to add a title in the center of the donut chart - const plugins = [ - { - id: 'donutTitle', - beforeDraw: chart => { - const { width } = chart; - const { height } = chart; - const { ctx } = chart; - - ctx.restore(); - const fontSize = (height / 240).toFixed(2); // Smaller font size - ctx.font = `${fontSize}em sans-serif`; - ctx.textBaseline = 'middle'; - ctx.fillStyle = darkMode ? '#ffffff' : '#000000'; - - const text = 'Materials'; - const textX = Math.round((width - ctx.measureText(text).width) / 2); - const textY = height / 2; - - ctx.fillText(text, textX, textY); - ctx.save(); - }, - }, - ]; - return ( -
-

- Material Usage Dashboard -

-
- {/* Filters Section */} -
-
-
-

Filters

-

- Select options to filter the chart data -

-
-
- {/* Project Filter */} -
- - + <> +
+
+

Material Usage Dashboard

+
+ {/* Filters Section */} +
+
+
+

Filters

+

Select options to filter the chart data

+
+ {/* Project Filter */} +
+ + +
- {/* Material Type Filter */} -
- - -
+ {/* Material Type Filter */} +
+ + +
- {/* Increase Over Last Week Filter */} -
- setShowIncreaseOnly(e.target.checked)} - className={styles.checkboxInput} - /> - + {/* Increase Over Last Week Filter */} +
+ setShowIncreaseOnly(e.target.checked)} + className={styles.checkboxInput} + /> + +
-
- {/* Increase Counter */} - {showIncreaseOnly && increasePercentage !== 0 && ( -
-
- Usage Trend -
-
- 0 - ? `${styles.trendBadge} ${styles.trendBadgeIncrease}` - : `${styles.trendBadge} ${styles.trendBadgeDecrease}` - } - > - {increasePercentage > 0 ? '↑' : '↓'} {Math.abs(increasePercentage).toFixed(1)}% - - - {increasePercentage > 0 - ? 'Increase in material usage' - : 'Decrease in material usage'}{' '} - compared to last week - + {/* Increase Counter */} + {showIncreaseOnly && increasePercentage !== 0 && ( +
+
Usage Trend
+
+ 0 + ? `${styles.trendBadge} ${styles.trendBadgeIncrease}` + : `${styles.trendBadge} ${styles.trendBadgeDecrease}` + } + > + {increasePercentage > 0 ? '↑' : '↓'} {Math.abs(increasePercentage).toFixed(1)}% + + + {increasePercentage > 0 + ? 'Increase in material usage' + : 'Decrease in material usage'}{' '} + compared to last week + +
-
- )} -
+ )} +
- {/* Chart Section */} -
-
-
-

- Material Usage Breakdown - {selectedMaterial !== 'all' && - ` - ${selectedMaterial.charAt(0).toUpperCase() + selectedMaterial.slice(1)}`} -

-

- {mockProjects.find(p => p.id === selectedProject)?.name} -

-
-
- {loading && ( -
-
-

Loading data...

-
- )} - {!loading && chartData && ( -
- +
+
+

+ Material Usage Breakdown + {selectedMaterial !== 'all' && + ` - ${selectedMaterial.charAt(0).toUpperCase() + selectedMaterial.slice(1)}`} +

+

+ {mockProjects.find(p => p.id === selectedProject)?.name} +

+
+
+ {loading && ( +
+
+

Loading data...

+
+ )} + {!loading && chartData && ( +
+ { - const label = context.label || ''; - const value = context.raw || 0; - return `${label} (${value} units)`; + tooltip: { + callbacks: { + label: context => { + const label = context.label || ''; + const value = context.raw || 0; + return `${label} (${value} units)`; + }, }, }, }, - }, - }} - plugins={plugins} - /> -
- )} - {!loading && !chartData &&

No data available

} -
- {/* Material Breakdown List */} - {chartData && !loading && ( -
-

Material Breakdown

-
- {chartData.datasets[0].data.map((value, index) => { - const label = chartData.labels[index].split(':')[0]; - const color = chartData.datasets[0].backgroundColor[index]; - return ( -
+ }} + plugins={[ + { + id: 'donutTitle', + afterDatasetsDraw(chart) { + const { width, height } = chart; + const ctx = chart.ctx; + + ctx.save(); + + // Get the center point + const centerX = width / 2; + const centerY = height / 2; + + // Set text properties + const fontSize = Math.floor(height / 12); + ctx.font = `bold ${fontSize}px 'Helvetica Neue', Helvetica, Arial, sans-serif`; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillStyle = darkMode ? '#ffffff' : '#1a1a1a'; + + // Draw text + const text = 'Materials'; + ctx.fillText(text, centerX, centerY); + + ctx.restore(); + }, + }, + ]} + /> +
+ )} + {!loading && !chartData &&

No data available

} +
+ {/* Material Breakdown List */} + {chartData && !loading && ( +
+

Material Breakdown

+
+ {chartData.datasets[0].data.map((value, index) => { + const label = chartData.labels[index].split(':')[0]; + const color = chartData.datasets[0].backgroundColor[index]; + return (
-
-

- {label} -

-

- {value}{' '} - - units - -

+ key={`${chartData.labels[index]}-${value}`} + className={styles.materialBreakdownItem} + > +
+
+

{label}

+

+ {value} units +

+
-
- ); - })} + ); + })} +
-
- )} + )} +
-
+ ); } diff --git a/src/components/MaterialSummary/MaterialSummary.module.css b/src/components/MaterialSummary/MaterialSummary.module.css index 46e601a0e6..dfd79dd6c1 100644 --- a/src/components/MaterialSummary/MaterialSummary.module.css +++ b/src/components/MaterialSummary/MaterialSummary.module.css @@ -1,74 +1,75 @@ .dashboardWrapper { - max-width: 1200px; - margin: 0 auto; - padding: 16px; -} - -.dashboardTitle { - font-size: 1.875rem; - font-weight: bold; - margin-bottom: 24px; -} - -.gridContainer { - display: grid; - gap: 24px; -} - -@media (min-width: 1024px) { - .gridContainer { - grid-template-columns: 1fr 3fr; - } -} - -.filterPanel { - display: flex; - flex-direction: column; - gap: 24px; -} - -.filterCard { - background: white; - border-radius: 8px; - box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1); - padding: 16px; + width: 100%; + padding: 0; + margin: 0; + background-color: var(--bg-color); + min-height: calc(100vh - 70px); + transition: background-color 0.3s ease, color 0.3s ease; + --bg-color: #f3f4f6; + --text-color: #000; + --card-bg: #ffffff; + --card-shadow: 0 4px 6px -1px rgba(0,0,0,0.1); + --secondary-text: #6b7280; + --border-color: #d1d5db; + --input-bg: #fff; + --input-text: #000; + --input-border: #d1d5db; + --accent-card: #f9fafb; + display: block; + visibility: visible; } -.filterCardTitle { - font-size: 1.25rem; - font-weight: 600; - margin-bottom: 4px; +.dashboardWrapper.darkMode { + --bg-color: #1B2A41; + --text-color: #f1f1f1; + --card-bg: #2a3f5f; + --card-shadow: 0 4px 6px -1px rgba(0,0,0,0.3); + --secondary-text: #b0b0b0; + --border-color: #4a5f7f; + --input-bg: #1f3a52; + --input-text: #f1f1f1; + --input-border: #4a5f7f; + --accent-card: #1f3a52; } -.filterCardDesc { - color: #6b7280; - font-size: 0.875rem; +.dashboardTitle { + font-size: 2rem; + font-weight: 700; + margin: 0; + padding: 28px 40px 24px 40px; + color: var(--text-color); + text-align: center; + border-bottom: 1px solid var(--border-color); } .filterFields { display: flex; flex-direction: column; - gap: 16px; + gap: 18px; + margin-top: 8px; } .fieldGroup { display: flex; flex-direction: column; - gap: 8px; + gap: 6px; } .fieldLabel { display: block; font-size: 0.875rem; font-weight: 500; + color: var(--text-color); } .selectInput { width: 100%; padding: 8px; - border: 1px solid #d1d5db; + border: 1px solid var(--input-border); border-radius: 6px; outline: none; + background-color: var(--input-bg); + color: var(--input-text); } .checkboxGroup { @@ -86,19 +87,22 @@ .checkboxLabel { font-size: 0.875rem; cursor: pointer; + color: var(--text-color); } .increaseCard { - background: white; + background: var(--card-bg); border-radius: 8px; - box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1); + box-shadow: var(--card-shadow); padding: 16px; + color: var(--text-color); } .increaseCardTitle { font-size: 1.25rem; font-weight: 600; margin-bottom: 8px; + color: var(--text-color); } .increaseTrendRow { @@ -127,22 +131,28 @@ .increaseText { margin-left: 8px; font-size: 0.875rem; + color: var(--text-color); } .chartPanel { - background: white; + background: var(--card-bg); border-radius: 8px; - box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1); - padding: 16px; + box-shadow: var(--card-shadow); + padding: 20px; + color: var(--text-color); + visibility: visible; + display: block; + width: 100%; } .chartPanelTitle { font-size: 1.25rem; font-weight: 600; + color: var(--text-color); } .chartPanelDesc { - color: #6b7280; + color: var(--secondary-text); font-size: 0.875rem; } @@ -150,7 +160,8 @@ display: flex; justify-content: center; align-items: center; - min-height: 220px; + min-height: 280px; + margin: 24px 0; } .loadingArea { @@ -176,7 +187,7 @@ .materialBreakdown { margin-top: 24px; - border-top: 1px solid #e5e7eb; + border-top: 1px solid var(--border-color); padding-top: 16px; } @@ -184,40 +195,107 @@ font-size: 1.125rem; font-weight: 500; margin-bottom: 12px; + color: var(--text-color); } .materialBreakdownGrid { display: grid; - grid-template-columns: repeat(auto-fit, minmax(200px,1fr)); - gap: 16px; + grid-template-columns: repeat(3, 1fr); + gap: 20px; + margin-top: 16px; } .materialBreakdownItem { display: flex; + flex-direction: column; align-items: center; + justify-content: center; gap: 12px; - padding: 12px; - border-radius: 6px; - background: #f9fafb; + padding: 16px; + border-radius: 8px; + background: var(--accent-card); + color: var(--text-color); + text-align: center; } .materialBreakdownDot { - width: 16px; - height: 16px; + width: 14px; + height: 14px; border-radius: 50%; + flex-shrink: 0; } .materialBreakdownName { - font-weight: 500; + font-weight: 600; + color: var(--text-color); + font-size: 0.95rem; } .materialBreakdownValue { - font-size: 1.5rem; + font-size: 1.75rem; font-weight: bold; + color: var(--text-color); + margin-top: 4px; } .materialBreakdownUnit { font-size: 0.875rem; - color: #6b7280; + color: var(--secondary-text); font-weight: normal; } + +.gridContainer { + display: grid; + gap: 32px; + align-items: start; + grid-template-columns: 320px 1fr; + max-width: 100%; + margin: 0; + padding: 32px 40px; + visibility: visible; + width: 100%; +} + +@media (max-width: 1024px) { + .gridContainer { + grid-template-columns: 1fr; + padding: 32px 24px; + } +} + +.filterPanel { + display: flex; + flex-direction: column; + gap: 24px; +} + +.filterCard { + background: var(--card-bg); + border-radius: 8px; + box-shadow: var(--card-shadow); + padding: 20px; + color: var(--text-color); + height: fit-content; + visibility: visible; + display: block; +} + +.filterCardTitle { + font-size: 1.25rem; + font-weight: 600; + margin-bottom: 4px; + color: var(--text-color); +} + +.filterCardDesc { + color: var(--secondary-text); + font-size: 0.875rem; +} + +.filterCardHeader { + margin-bottom: 16px; +} + +.chartPanelHeader { + margin-bottom: 16px; +}