Skip to content

Commit dcd24e6

Browse files
committed
fix: longst open issues chart
1 parent b70f3ec commit dcd24e6

2 files changed

Lines changed: 145 additions & 89 deletions

File tree

Lines changed: 95 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,129 @@
1-
/* issueChart.module.css */
1+
.chartContainer {
2+
width: 100%;
3+
height: 500px;
4+
}
25

3-
.issueChartEventContainer {
4-
max-width: 900px;
5-
margin: 0 auto;
6+
/* Container for entire chart section */
7+
.issueChartContainer {
8+
width: 50vw; /* full viewport width */
69
padding: 20px;
10+
box-sizing: border-box; /* include padding in width */
711
background: #f9f9f9;
812
border-radius: 8px;
913
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
1014
}
1115

12-
.issueChartEventContainerDark {
16+
17+
.filterCenterWrapper {
18+
max-width: 650px; /* filters centered and constrained */
19+
margin: 0 auto 20px auto;
20+
}
21+
22+
23+
.issueChartContainerDark {
24+
width: 50vw; /* full viewport width */
25+
padding: 20px;
26+
box-sizing: border-box; /* include padding in width */
1327
background: #121212;
1428
box-shadow: 0 4px 12px rgba(0,0,0,0.9);
1529
color: #ccd1dc;
1630
}
1731

18-
.issueChartEventTitle {
32+
/* Chart title */
33+
.title {
1934
text-align: center;
2035
font-size: 24px;
36+
font-weight: bold;
37+
margin-bottom: 20px;
2138
color: #333;
2239
}
2340

24-
.issueChartEventTitleDark {
41+
.titleDark {
42+
text-align: center;
43+
font-size: 24px;
44+
font-weight: bold;
45+
margin-bottom: 20px;
2546
color: #fff;
2647
}
2748

28-
.chartWrapper {
29-
padding: 20px;
30-
background: #fff;
31-
border-radius: 8px;
32-
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
49+
/* Filter rows */
50+
.dateRow {
51+
display: grid;
52+
grid-template-columns: auto 1fr auto 1fr;
53+
align-items: center;
54+
gap: 10px;
55+
width: 100%;
56+
margin-bottom: 15px;
3357
}
3458

35-
.chartWrapperDark {
36-
background: #1e1e1e;
37-
box-shadow: 0 0 15px rgba(0,0,0,0.9);
38-
color: #ccd1dc;
59+
.projectRow {
60+
width: 100%;
3961
}
4062

41-
.issueChartLabel {
42-
font-size: 16px;
43-
color: #555;
63+
/* Labels */
64+
.dateLabel {
65+
font-size: 14px;
66+
font-weight: 500;
67+
color: #333;
4468
}
4569

46-
.issueChartLabelDark {
47-
color: #fff;
70+
.dark .dateLabel {
71+
color: #cfd7e3;
4872
}
4973

50-
.issueChartSelect {
51-
padding: 2px 10px;
52-
font-size: 16px;
53-
border-radius: 4px;
74+
/* Date picker */
75+
.dateField {
76+
width: 100%;
77+
}
78+
79+
.dateLight,
80+
.dateDark {
81+
width: 100%;
82+
padding: 8px 10px;
83+
border-radius: 6px;
5484
border: 1px solid #ccc;
55-
background-color: #fff;
56-
color: #333;
57-
cursor: pointer;
58-
transition: border-color 0.3s ease;
59-
outline: none;
60-
margin-bottom: 20px;
85+
font-size: 14px;
6186
}
6287

63-
.issueChartSelectDark {
88+
.dateDark {
89+
background: #22272e;
90+
color: #cfd7e3;
6491
border-color: #3d444d;
65-
background-color: #22272e;
92+
}
93+
94+
/* React select */
95+
.selectReact {
96+
width: 100%;
97+
}
98+
99+
.selectDark {
66100
color: #cfd7e3;
67101
}
102+
103+
/* No data text */
104+
.noData {
105+
text-align: center;
106+
color: #888;
107+
font-size: 16px;
108+
padding: 40px 0;
109+
}
110+
111+
/* Loading/Error */
112+
.loading,
113+
.error {
114+
text-align: center;
115+
padding: 20px 0;
116+
font-size: 16px;
117+
}
118+
119+
/* Responsive */
120+
@media (max-width: 650px) {
121+
.dateRow {
122+
grid-template-columns: 1fr;
123+
gap: 10px;
124+
}
125+
126+
.dateRow span.dateLabel {
127+
display: none; /* hide labels for small screens */
128+
}
129+
}

src/components/BMDashboard/Issues/openIssueCharts.jsx

Lines changed: 50 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect, useState, useRef } from 'react';
1+
import { useEffect, useState, useRef, useMemo } from 'react';
22
import DatePicker from 'react-datepicker';
33
import 'react-datepicker/dist/react-datepicker.css';
44
import { useDispatch, useSelector } from 'react-redux';
@@ -8,7 +8,6 @@ import {
88
XAxis,
99
YAxis,
1010
CartesianGrid,
11-
Tooltip,
1211
ResponsiveContainer,
1312
LabelList,
1413
} from 'recharts';
@@ -18,24 +17,36 @@ import {
1817
fetchLongestOpenIssues,
1918
setProjectFilter,
2019
} from '../../../actions/bmdashboard/issueChartActions';
21-
import './issueCharts.css';
20+
import styles from './issueChart.module.css';
2221

2322
function IssueCharts() {
2423
const dispatch = useDispatch();
24+
2525
const { issues, loading, error, selectedProjects } = useSelector(state => state.bmissuechart);
2626
const projects = useSelector(state => state.bmProjects);
27+
const darkMode = useSelector(state => state.theme?.darkMode);
28+
2729
const [startDate, setStartDate] = useState(null);
2830
const [endDate, setEndDate] = useState(null);
2931
const chartContainerRef = useRef(null);
3032
const [containerWidth, setContainerWidth] = useState(window.innerWidth);
3133

34+
// Normalize issues for chart
35+
const normalizedIssues = useMemo(() => {
36+
return (issues || []).map((item, index) => ({
37+
issueName: item.issueName || `Issue #${index + 1}`,
38+
durationOpen: item.durationOpen ?? 0,
39+
}));
40+
}, [issues]);
41+
42+
// Load projects on mount
3243
useEffect(() => {
3344
dispatch(fetchBMProjects());
3445
}, [dispatch]);
3546

47+
// Fetch issues when filters change
3648
useEffect(() => {
3749
let dateRange = [];
38-
3950
if (startDate && endDate) {
4051
dateRange = [
4152
`${startDate.toISOString().split('T')[0]},${endDate.toISOString().split('T')[0]}`,
@@ -50,14 +61,15 @@ function IssueCharts() {
5061
dispatch(fetchLongestOpenIssues(dateRange, selectedProjects));
5162
}, [dispatch, startDate, endDate, selectedProjects]);
5263

64+
// Handle chart container width
5365
useEffect(() => {
5466
function handleResize() {
5567
if (chartContainerRef.current) {
5668
setContainerWidth(chartContainerRef.current.offsetWidth);
5769
}
5870
}
5971
window.addEventListener('resize', handleResize);
60-
handleResize(); // Initial set
72+
handleResize();
6173
return () => window.removeEventListener('resize', handleResize);
6274
}, []);
6375

@@ -70,9 +82,7 @@ function IssueCharts() {
7082
label: project.name,
7183
}));
7284

73-
// Calculate margins and YAxis width based on container width
7485
const getChartLayout = () => {
75-
// Margins and YAxis width scale with container width
7686
const leftRightMargin = Math.max(20, Math.min(200, containerWidth * 0.12));
7787
const yAxisWidth = Math.max(60, Math.min(180, containerWidth * 0.13));
7888
return {
@@ -83,96 +93,80 @@ function IssueCharts() {
8393

8494
const { margin, yAxisWidth } = getChartLayout();
8595

86-
if (loading) return <div>Loading...</div>;
87-
if (error) return <div>Error: {error}</div>;
96+
if (loading) return <div className={styles.loading}>Loading...</div>;
97+
if (error) return <div className={styles.error}>Error: {error}</div>;
8898

8999
return (
90-
<div className="issue-chart-container">
91-
<h2>Longest Open Issues</h2>
92-
93-
<div className="filters-container">
94-
<div className="filter">
95-
<label className="issue-chart-label" htmlFor="start-date">
96-
Date Range:
97-
</label>
98-
<div className="date-range-picker">
100+
<div className={darkMode ? styles.issueChartContainerDark : styles.issueChartContainer}>
101+
<h2 className={darkMode ? styles.titleDark : styles.title}>Longest Open Issues</h2>
102+
103+
<div className={styles.filterCenterWrapper}>
104+
{/* Row 1: Date picker */}
105+
<div className={styles.dateRow}>
106+
<span className={styles.dateLabel}>From</span>
107+
<div className={styles.dateField}>
99108
<DatePicker
100-
id="start-date"
101109
selected={startDate}
102110
onChange={date => setStartDate(date)}
103-
selectsStart
104-
startDate={startDate}
105-
endDate={endDate}
106-
maxDate={endDate}
107111
placeholderText="Start Date"
108-
isClearable
109-
className="filter-select"
112+
className={darkMode ? styles.dateDark : styles.dateLight}
110113
/>
111-
<span>to</span>
114+
</div>
115+
<span className={styles.dateLabel}>to</span>
116+
<div className={styles.dateField}>
112117
<DatePicker
113118
selected={endDate}
114119
onChange={date => setEndDate(date)}
115-
selectsEnd
116-
startDate={startDate}
117-
endDate={endDate}
118-
minDate={startDate}
119-
maxDate={new Date()}
120120
placeholderText="End Date"
121-
isClearable
122-
className="filter-select"
121+
className={darkMode ? styles.dateDark : styles.dateLight}
123122
/>
124123
</div>
125124
</div>
126125

127-
<div className="filter">
128-
<label className="issue-chart-label" htmlFor="start-date">
129-
Projects:
130-
</label>
126+
{/* Row 2: Project selector */}
127+
<div className={styles.projectRow}>
131128
<Select
132-
id="start-date"
133129
isMulti
130+
id="project-select"
134131
options={projectOptions}
135132
onChange={handleProjectChange}
136133
value={projectOptions.filter(option => (selectedProjects ?? []).includes(option.value))}
137-
className="filter-select"
138134
classNamePrefix="select"
135+
className={`${styles.selectReact} ${darkMode ? styles.selectDark : ''}`}
139136
/>
140137
</div>
141138
</div>
142139

143-
<div className="chart-container" ref={chartContainerRef}>
144-
{!issues || issues.length === 0 ? (
145-
<div className="no-data-message">
146-
<div className="no-data-content">
147-
<h3>No Open Issues Found</h3>
148-
<p>There are currently no open issues matching your selected criteria.</p>
149-
<p>Try adjusting your date range or project filters to see more results.</p>
150-
</div>
151-
</div>
140+
{/* Chart */}
141+
<div className={styles.chartContainer} ref={chartContainerRef}>
142+
{normalizedIssues.length === 0 ? (
143+
<p className={styles.noData}>No issues found.</p>
152144
) : (
153145
<ResponsiveContainer width="100%" height="100%">
154-
<BarChart data={issues} layout="vertical" margin={margin}>
146+
<BarChart data={normalizedIssues} layout="vertical" margin={margin}>
155147
<CartesianGrid strokeDasharray="3 3" />
156148
<XAxis
157149
type="number"
158-
label={{ value: 'Duration in Months', position: 'insideBottom', offset: -5 }}
150+
label={{
151+
value: 'Duration in Months',
152+
position: 'insideBottom',
153+
offset: -5,
154+
fill: darkMode ? '#fff' : '#000',
155+
}}
156+
tick={{ fill: darkMode ? '#ccc' : '#333' }}
159157
/>
160158
<YAxis
161159
dataKey="issueName"
162160
type="category"
163-
tick={{ fontSize: 14, fontWeight: 500 }}
161+
tick={{ fontSize: 14, fontWeight: 500, fill: darkMode ? '#fff' : '#000' }}
164162
width={yAxisWidth}
165163
/>
166-
<Tooltip
167-
formatter={value => `${value} months`}
168-
labelFormatter={label => `Issue: ${label}`}
169-
/>
170164
<Bar dataKey="durationOpen" fill="#6495ED" barSize={30}>
171165
<LabelList
172166
dataKey="durationOpen"
173167
position="right"
174168
formatter={v => `${v} mo`}
175-
className="recharts-label"
169+
fill={darkMode ? '#fff' : '#000'}
176170
/>
177171
</Bar>
178172
</BarChart>

0 commit comments

Comments
 (0)