Skip to content

Commit 9877dea

Browse files
Merge pull request #5015 from OneCommunityGlobal/Sayali_Fix_ReportsPeople_DarkMode
Sayali: dark mode background for Reports People page
2 parents 0a0460d + d8c5e21 commit 9877dea

8 files changed

Lines changed: 328 additions & 458 deletions

File tree

Lines changed: 76 additions & 177 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
/* eslint-disable testing-library/no-node-access */
2-
import React from 'react';
32
import * as d3 from 'd3';
4-
3+
import React from 'react';
54
import { Button, Modal } from 'react-bootstrap';
6-
import styles from './PeopleReport/PeopleReport.module.css';
75
import { boxStyle, boxStyleDark } from '../../styles';
6+
import styles from './PeopleReport/PeopleReport.module.css';
7+
import {
8+
createAxes,
9+
createDots,
10+
createLabels,
11+
createLegend,
12+
createLine,
13+
createSvgRoot,
14+
createTooltip,
15+
} from './d3GraphUtils';
816

917
function InfringementsViz({ infringements, fromDate, toDate, darkMode }) {
1018
const [graphVisible, setGraphVisible] = React.useState(false);
@@ -18,197 +26,97 @@ function InfringementsViz({ infringements, fromDate, toDate, darkMode }) {
1826

1927
const handleModalShow = d => {
2028
setFocusedInf(d);
21-
if (graphVisible === false) {
22-
setModalVisible(!modalVisible);
23-
}
24-
setGraphVisible(!graphVisible); // Open the graph when opening the modal
29+
if (graphVisible === false) setModalVisible(!modalVisible);
30+
setGraphVisible(!graphVisible);
2531
};
32+
2633
function displayGraph(bsCount, maxSquareCount) {
2734
if (!graphVisible) {
2835
d3.selectAll('#infplot > *').remove();
2936
} else {
3037
d3.selectAll('#infplot > *').remove();
38+
3139
const margin = { top: 30, right: 20, bottom: 30, left: 20 };
3240
const containerWidth = '1000';
33-
// Adjusted width based on the available space
3441
const width = Math.min(containerWidth - margin.left - margin.right, 1000);
35-
3642
const height = 400 - margin.top - margin.bottom;
3743

38-
const tooltipEl = function tooltipEl(d) {
39-
return (
40-
`${'<div class="tip__container">' +
41-
'<div class="close">' +
42-
'<button>&times</button>' +
43-
'</div>' +
44-
'<div>' +
45-
'Exact date: '}${d3.timeFormat('%A, %B %e, %Y')(d.date)}<br>` +
46-
`Count: ${d.count === 1 ? d.count : `${d.count} <span class="detailsModal"><a>See All</a></span>`
47-
}<br>` +
48-
`Description: ${d.des[0]}</div>` +
49-
`</div>`
50-
);
51-
};
52-
53-
const legendEl = function legendEl() {
54-
return (
55-
'<div class="lengendSubContainer">' +
56-
'<div class="infLabelsOff">' +
57-
'<button>Labels Off</button>' +
58-
'</div>' +
59-
'<div class="infCountLabelsOn">' +
60-
'<button>Show Squares</button>' +
61-
'</div>' +
62-
'<div class="infDateLabelsOn">' +
63-
'<button>Show Dates</button>' +
64-
'</div>' +
65-
'</div>'
66-
);
67-
};
68-
69-
const svg = d3
70-
.select('#infplot')
71-
.append('svg')
72-
.attr('width', '100%')
73-
.attr('height', height + margin.top + margin.bottom)
74-
.attr('viewBox', `0 0 ${containerWidth} ${height + margin.top + margin.bottom}`)
75-
.append('g')
76-
.attr('transform', `translate(${margin.left},${margin.top})`);
77-
78-
const x = d3
79-
.scaleTime()
80-
.domain(d3.extent(bsCount, d => d.date))
81-
.range([0, width]);
82-
svg
83-
.append('g')
84-
.attr('transform', `translate(0, ${height})`)
85-
.call(d3.axisBottom(x));
86-
87-
const y = d3
88-
.scaleLinear()
89-
.domain([0, maxSquareCount + 2])
90-
.range([height, 0]);
91-
svg.append('g').call(
92-
d3
93-
.axisLeft(y)
94-
.ticks(5)
95-
.tickFormat(d3.format('d')),
96-
);
44+
const textColor = darkMode ? `color: #f9fafb;` : '';
45+
const legendHtml =
46+
`<div class="lengendSubContainer" style="${textColor}">` +
47+
`<div class="infLabelsOff"><button style="${textColor}">Labels Off</button></div>` +
48+
`<div class="infCountLabelsOn"><button style="${textColor}">Show Squares</button></div>` +
49+
`<div class="infDateLabelsOn"><button style="${textColor}">Show Dates</button></div>` +
50+
`</div>`;
9751

98-
svg
99-
.append('path')
100-
.datum(bsCount)
101-
.attr('fill', 'none')
102-
.attr('stroke', 'black')
103-
.attr('stroke-width', 1.5)
104-
.attr(
105-
'd',
106-
d3
107-
.line()
108-
.x(d => x(d.date))
109-
.y(d => y(d.count)),
110-
);
111-
112-
svg
113-
.append('g')
114-
.selectAll('dot')
115-
.data(bsCount)
116-
.join('circle')
117-
.attr('class', 'myCircle')
118-
.attr('cx', d => x(d.date))
119-
.attr('cy', d => y(d.count))
120-
.attr('r', 3)
121-
.attr('stroke', '#69b3a2')
122-
.attr('stroke-width', 3)
123-
.attr('fill', 'white')
124-
.on('click', function handleCircleClick(event, d) {
125-
const prevTooltip = d3.select(`.inf${d.id}`);
52+
const svgRoot = createSvgRoot('#infplot', containerWidth, height, margin, darkMode);
53+
const svg = svgRoot.append('g').attr('transform', `translate(${margin.left},${margin.top})`);
12654

127-
if (prevTooltip.empty()) {
128-
const Tooltip = d3
129-
.select('#infplot')
130-
.append('div')
131-
.style('opacity', 0)
132-
.attr('class', `tooltip inf${d.id}`)
133-
.style('background-color', 'white')
134-
.style('border', 'solid')
135-
.style('border-width', '2px')
136-
.style('border-radius', '5px')
137-
.style('padding', '5px')
138-
.style('max-width', '500px')
139-
.style('z-index', 1000);
55+
const x = d3.scaleTime().domain(d3.extent(bsCount, d => d.date)).range([0, width]);
56+
const y = d3.scaleLinear().domain([0, maxSquareCount + 2]).range([height, 0]);
14057

141-
Tooltip.html(tooltipEl(d))
142-
.style('left', `${event.pageX + 10}px`)
143-
.style('top', `${event.pageY}px`)
144-
.style('opacity', 1);
145-
146-
Tooltip.select('.close').on('click', function handleCloseClick() {
147-
Tooltip.remove();
148-
});
149-
150-
Tooltip.select('.detailsModal').on('click', function handleDetailsModalClick() {
151-
handleModalShow(d);
152-
});
153-
}
154-
});
58+
createAxes(svg, x, y, height, darkMode);
15559

15660
svg
15761
.append('g')
62+
.call(d3.axisLeft(y).ticks(5).tickFormat(d3.format('d')))
15863
.selectAll('text')
159-
.data(bsCount)
160-
.join('text')
161-
.attr('class', 'infCountLabel')
162-
.attr('x', d => x(d.date) + 10)
163-
.attr('y', d => y(d.count) - 5)
164-
.attr('fill', 'black')
165-
.style('z-index', 999)
166-
.style('font-weight', 700)
167-
.style('display', 'none')
168-
.text(d => parseInt(d.count, 10));
64+
.attr('fill', darkMode ? '#f9fafb' : 'black');
65+
66+
createLine(svg, bsCount, x, y, darkMode);
67+
68+
const dots = createDots(svg, bsCount, x, y);
69+
dots.on('click', function handleCircleClick(event, d) {
70+
const prevTooltip = d3.select(`.inf${d.id}`);
71+
if (prevTooltip.empty()) {
72+
const Tooltip = createTooltip('#infplot', d, darkMode);
73+
Tooltip.attr('class', `tooltip inf${d.id}`)
74+
.style('max-width', '500px')
75+
.html(
76+
`<div class="tip__container"><div class="close">` +
77+
`<button style="color: ${darkMode ? '#f9fafb' : 'black'}; background: transparent; border: none;">&times</button>` +
78+
`</div><div>Exact date: ${d3.timeFormat('%A, %B %e, %Y')(d.date)}<br>` +
79+
`Count: ${d.count === 1 ? d.count : `${d.count} <span class="detailsModal"><a>See All</a></span>`}<br>` +
80+
`Description: ${d.des[0]}</div></div>`
81+
)
82+
.style('left', `${event.pageX + 10}px`)
83+
.style('top', `${event.pageY}px`)
84+
.style('opacity', 1);
85+
86+
Tooltip.select('.close').on('click', function handleCloseClick() {
87+
Tooltip.remove();
88+
});
89+
Tooltip.select('.detailsModal').on('click', function handleDetailsModalClick() {
90+
handleModalShow(d);
91+
});
92+
}
93+
});
16994

170-
svg
171-
.append('g')
172-
.selectAll('text')
173-
.data(bsCount)
174-
.join('text')
175-
.attr('class', 'infDateLabel')
176-
.attr('x', d => x(d.date) + 10)
177-
.attr('y', d => y(d.count) - 5)
178-
.attr('fill', 'black')
179-
.style('z-index', 999)
180-
.style('font-weight', 700)
181-
.style('display', 'none')
182-
.text(d => d3.timeFormat('%m/%d/%Y')(d.date));
95+
createLabels(svg, bsCount, x, y, 'infCountLabel', darkMode, d => parseInt(d.count, 10));
96+
createLabels(svg, bsCount, x, y, 'infDateLabel', darkMode, d => d3.timeFormat('%m/%d/%Y')(d.date));
18397

184-
const legend = d3
185-
.select('#infplot')
186-
.append('div')
187-
.attr('class', 'legendContainer');
188-
legend.html(legendEl());
98+
const legend = createLegend('#infplot', legendHtml);
18999

190100
legend.select('.infLabelsOff').on('click', function handleLabelsOffClick() {
191101
d3.selectAll('.infCountLabel').style('display', 'none');
192102
d3.selectAll('.infDateLabel').style('display', 'none');
193103
});
194-
195104
legend.select('.infCountLabelsOn').on('click', function handleCountLabelsOnClick() {
196105
d3.selectAll('.infCountLabel').style('display', 'block');
197106
d3.selectAll('.infDateLabel').style('display', 'none');
198107
});
199-
200108
legend.select('.infDateLabelsOn').on('click', function handleDateLabelsOnClick() {
201109
d3.selectAll('.infDateLabel').style('display', 'block');
202110
d3.selectAll('.infCountLabel').style('display', 'none');
203111
});
204112
}
205113
}
114+
206115
const generateGraph = () => {
207116
const dict = {};
208117
const value = [];
209118
let maxSquareCount = 0;
210119

211-
// aggregate infringements
212120
for (let i = 0; i < infringements.length; i += 1) {
213121
if (infringements[i].date in dict) {
214122
dict[infringements[i].date].ids.push(infringements[i]._id);
@@ -223,11 +131,8 @@ function InfringementsViz({ infringements, fromDate, toDate, darkMode }) {
223131
}
224132
}
225133

226-
// filter infringements by date
227134
if (fromDate === '' || toDate === '') {
228-
// condition no longer needed
229135
Object.keys(dict).forEach(key => {
230-
// Use if statement to filter unwanted properties from the prototype chain
231136
if (Object.prototype.hasOwnProperty.call(dict, key)) {
232137
value.push({
233138
date: d3.timeParse('%Y-%m-%d')(key),
@@ -236,9 +141,7 @@ function InfringementsViz({ infringements, fromDate, toDate, darkMode }) {
236141
type: 'Infringement',
237142
ids: dict[key].ids,
238143
});
239-
if (dict[key].count > maxSquareCount) {
240-
maxSquareCount = dict[key].count;
241-
}
144+
if (dict[key].count > maxSquareCount) maxSquareCount = dict[key].count;
242145
}
243146
});
244147
} else {
@@ -253,9 +156,7 @@ function InfringementsViz({ infringements, fromDate, toDate, darkMode }) {
253156
type: 'Infringement',
254157
ids: dict[key].ids,
255158
});
256-
if (dict[key].count > maxSquareCount) {
257-
maxSquareCount = dict[key].count;
258-
}
159+
if (dict[key].count > maxSquareCount) maxSquareCount = dict[key].count;
259160
counter += 1;
260161
}
261162
});
@@ -273,40 +174,38 @@ function InfringementsViz({ infringements, fromDate, toDate, darkMode }) {
273174
<Button onClick={handleModalShow} aria-expanded={graphVisible} style={darkMode ? boxStyleDark : boxStyle}>
274175
{graphVisible ? 'Hide Infringements Graph' : 'Show Infringements Graph'}
275176
</Button>
276-
<div className={`${styles.kaitest} ${darkMode ? 'bg-light mt-2' : ''}`} id="infplot" data-testid="infplot" />
177+
<div className={`${styles.kaitest} ${darkMode ? 'mt-2' : ''}`} id="infplot" data-testid="infplot" />
277178

278179
<Modal size="lg" show={modalVisible} onHide={handleModalClose}>
279-
<Modal.Header closeButton>
180+
<Modal.Header closeButton style={darkMode ? { backgroundColor: '#1b2a41', color: '#f9fafb', borderColor: '#374151' } : {}}>
280181
<Modal.Title>{focusedInf.date ? focusedInf.date.toString() : 'Infringement'}</Modal.Title>
281182
</Modal.Header>
282-
<Modal.Body>
183+
<Modal.Body style={darkMode ? { backgroundColor: '#1b2a41', color: '#f9fafb' } : {}}>
283184
<div id="inf">
284-
<table>
185+
<table style={darkMode ? { backgroundColor: '#1b2a41', color: '#f9fafb', width: '100%' } : { width: '100%' }}>
285186
<thead>
286-
<tr>
287-
<th>Descriptions</th>
187+
<tr style={darkMode ? { backgroundColor: '#1b2a41' } : {}}>
188+
<th style={darkMode ? { backgroundColor: '#1b2a41', color: '#f9fafb' } : {}}>Descriptions</th>
288189
</tr>
289190
</thead>
290191
<tbody>
291192
{focusedInf.des
292-
? focusedInf.des.map((desc) => (
293-
<tr key={desc}>
294-
<td>{desc}</td>
193+
? focusedInf.des.map(desc => (
194+
<tr key={desc} style={darkMode ? { backgroundColor: '#1b2a41' } : {}}>
195+
<td style={darkMode ? { backgroundColor: '#1b2a41', color: '#f9fafb' } : {}}>{desc}</td>
295196
</tr>
296197
))
297198
: null}
298199
</tbody>
299200
</table>
300201
</div>
301202
</Modal.Body>
302-
<Modal.Footer>
303-
<Button variant="secondary" onClick={handleModalClose}>
304-
Close
305-
</Button>
203+
<Modal.Footer style={darkMode ? { backgroundColor: '#1b2a41', borderColor: '#374151' } : {}}>
204+
<Button variant="secondary" onClick={handleModalClose}>Close</Button>
306205
</Modal.Footer>
307206
</Modal>
308207
</div>
309208
);
310209
}
311210

312-
export default InfringementsViz;
211+
export default InfringementsViz;

0 commit comments

Comments
 (0)