Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,14 @@
import { Doughnut } from 'react-chartjs-2';
import ChartDataLabels from 'chartjs-plugin-datalabels';
import { Chart, ArcElement } from 'chart.js';
import './VolunteerStatusPieChart.css';
import styles from './VolunteerStatusPieChart.module.css';

Chart.register(ArcElement);
Chart.register(ArcElement, ChartDataLabels);

function VolunteerStatusPieChart({
data: { totalVolunteers, percentageChange, data: volunteerData },
comparisonType,
}) {
// Debug: Log the data used for the chart
// console.log('VolunteerStatusPieChart data:', { volunteerData, totalVolunteers });
const chartData = {
labels: volunteerData.map(item => item.label),
datasets: [
Expand All @@ -28,43 +26,45 @@
datalabels: {
color: '#000',
font: {
size: 20,
weight: 'bolder',
lineHeight: 1.8,
size: 16,
weight: 'bold',
lineHeight: 1.4,
},
formatter: function(value, context) {
const percentage = ((value / totalVolunteers) * 100).toFixed(0);
// Show value and percent as two lines for clarity
return [`${value}`, `(${percentage}%)`];
formatter(value) {
const percentage = (value / totalVolunteers) * 100;
// Only show labels for slices >= 10%
if (percentage < 10) return '';
return `${value} (${percentage.toFixed(0)}%)`;
},
display: true,
offset: 0,
align: 'center',
anchor: 'center',
align: 'center',
offset: 0,
clamp: true,
},
legend: {
display: false,
},
tooltip: {
enabled: false,
},
legend: { display: false },
tooltip: { enabled: false },
},
maintainAspectRatio: false,
cutout: '55%',
cutout: '65%',
};

const percentageChangeColor = percentageChange >= 0 ? 'green' : 'red';

return (
<section className="volunteer-status-container" aria-label="Volunteer Status Overview">
<div className="volunteer-status-chart" role="img" aria-label="Volunteer Status Pie Chart">
<Doughnut data={chartData} options={options} plugins={[ChartDataLabels]} />
<div className="volunteer-status-center">
<h2 className="volunteer-status-heading">TOTAL VOLUNTEERS</h2>
<p className="volunteer-count">{totalVolunteers}</p>
<section className={styles.volunteerStatusContainer} aria-label="Volunteer Status Overview">
<div
className={styles.volunteerStatusChart}
role="img"
aria-label="Volunteer Status Pie Chart"
>

Check warning on line 60 in src/components/TotalOrgSummary/VolunteerStatus/VolunteerStatusPieChart.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use <img alt=...>, or <img alt=...> instead of the "img" role to ensure accessibility across all devices.

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZq9dqGNmMsW2NaM1q6Q&open=AZq9dqGNmMsW2NaM1q6Q&pullRequest=4456
<Doughnut data={chartData} options={options} />
<div className={styles.volunteerStatusCenter}>
<h2 className={styles.volunteerStatusHeading}>TOTAL VOLUNTEERS</h2>
<p className={styles.volunteerCount}>{totalVolunteers}</p>
{comparisonType !== 'No Comparison' && (
<p
className="percentage-change"
className={styles.percentageChange}
style={{ color: percentageChangeColor }}
aria-label={`Percentage change: ${percentageChange}% ${comparisonType.toLowerCase()}`}
>
Expand All @@ -75,17 +75,26 @@
)}
</div>
</div>
<div className="volunteer-status-labels">
{volunteerData.map((item, index) => (
<div key={item.label} className="volunteer-status-label">
<span
className="volunteer-status-color"
style={{ backgroundColor: chartData.datasets[0].backgroundColor[index] }}
aria-hidden="true"
/>
<span>{item.label}</span>
</div>
))}

<div className={styles.volunteerStatusLabels}>
{volunteerData.map((item, index) => {
const percentage = ((item.value / totalVolunteers) * 100).toFixed(1);
return (
<div key={item.label} className={styles.volunteerStatusLabel}>
<span
className={styles.volunteerStatusColor}
style={{
backgroundColor: chartData.datasets[0].backgroundColor[index],
}}
aria-hidden="true"
/>
<span>{item.label}</span>
<span className={styles.volunteerStatusValue}>
{item.value} ({percentage}%)
</span>
</div>
);
})}
</div>
</section>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,47 @@
.volunteer-status-container {
.volunteerStatusContainer {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
}

.volunteer-status-chart {
.volunteerStatusChart {
position: relative;
width: 100%;
max-width: 400px;
height: 400px;
}

.volunteer-status-center {
.volunteerStatusLabels {
display: flex;
justify-content: center;
gap: 24px;
margin-top: 20px;
margin-bottom: 50px;
flex-wrap: wrap;
}

.volunteerStatusLabel {
display: flex;
align-items: center;
gap: 6px;
font-size: 14px;
}

.volunteerStatusValue {
font-weight: 600;
}

.volunteerStatusColor {
display: inline-block;
width: 12px;
height: 12px;
margin-right: 5px;
}

/* Center text inside the donut */
.volunteerStatusCenter {
position: absolute;
top: 50%;
left: 50%;
Expand All @@ -22,41 +50,19 @@
font-size: 14px;
}

.volunteer-status-center .volunteer-status-heading {
.volunteerStatusHeading {
color: #828282;
font-size: 1.2rem;
}

.volunteer-status-center .volunteer-count {
.volunteerCount {
color: #6c6c6c;
font-size: 2rem;
font-weight: bolder;
}

.volunteer-status-center > p {
/* Optional: style for comparison text */
.percentageChange {
font-weight: bold;
}

.volunteer-status-center div {
margin: 2px 0;
}

.volunteer-status-labels {
display: flex;
justify-content: center;
margin-top: 20px;
margin-bottom: 50px;
}

.volunteer-status-label {
display: flex;
align-items: center;
margin: 0 10px;
}

.volunteer-status-color {
display: inline-block;
width: 12px;
height: 12px;
margin-right: 5px;
margin-top: 4px;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import { LineChart, Line, CartesianGrid, XAxis, YAxis, Tooltip } from 'recharts';
import {
LineChart,
Line,
CartesianGrid,
XAxis,
YAxis,
Tooltip,
ResponsiveContainer,
} from 'recharts';
import { useEffect, useState } from 'react';
import axios from 'axios';
import DatePicker from 'react-datepicker';
Expand Down Expand Up @@ -55,7 +63,7 @@
const [data, setData] = useState(null);
const [fetchError, setFetchError] = useState(false);
const latestNumberOfHours = data?.[data.length - 1].totalHours || 0;
const [chartSize, setChartSize] = useState({ width: null, height: null });

Check warning on line 66 in src/components/TotalOrgSummary/VolunteerTrendsLineChart/VolunteerTrendsLineChart.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove the declaration of the unused 'chartSize' variable.

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZq9dqU4mMsW2NaM1q6R&open=AZq9dqU4mMsW2NaM1q6R&pullRequest=4456

Check warning on line 66 in src/components/TotalOrgSummary/VolunteerTrendsLineChart/VolunteerTrendsLineChart.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this useless assignment to variable "chartSize".

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZq9dqU4mMsW2NaM1q6S&open=AZq9dqU4mMsW2NaM1q6S&pullRequest=4456
const [requestTimeFrame, setRequestTimeFrame] = useState(1);
const [requestOffset, setRequestOffset] = useState('week');
const [showDatePicker, setShowDatePicker] = useState(false);
Expand Down Expand Up @@ -265,43 +273,46 @@
</div>
</div>
) : (
<LineChart
width={chartSize.width}
height={chartSize.height}
data={data}
margin={{ right: 50, top: 50, left: 20 }}
>
<CartesianGrid stroke="#ccc" vertical={false} />
<XAxis
dataKey="xLabel"
axisLine={false}
tickLine={false}
tick={{ fill: darkMode ? '#ccc' : undefined }}
/>
<YAxis
tickFormatter={formatNumber}
axisLine={false}
tickLine={false}
tick={{ fill: darkMode ? '#ccc' : undefined }}
label={{
value: 'Total Hours',
angle: -90,
position: 'insideLeft',
dy: 20,
dx: -15,
style: { fontSize: 18, fill: darkMode ? '#ccc' : undefined },
}}
/>
<Line
type="linear"
dataKey="totalHours"
stroke="#328D1B"
strokeWidth={4}
dot={renderCustomDot}
strokeLinecap="round"
/>
<Tooltip content={renderCustomTooltip} />
</LineChart>
<div style={{ width: '100%', height: 350 }}>
<ResponsiveContainer width="100%" height="100%">
<LineChart data={data} margin={{ top: 50, right: 50, left: 70, bottom: 30 }}>
<CartesianGrid stroke="#ccc" vertical={false} />

<XAxis
dataKey="xLabel"
axisLine={false}
tickLine={false}
padding={{ left: 20, right: 20 }} // keeps first/last points away from the edges
tick={{ fill: darkMode ? '#ccc' : undefined }}
/>

<YAxis
tickFormatter={formatNumber}
axisLine={false}
tickLine={false}
domain={[0, 'dataMax']} // aligns Y range to your data
tick={{ fill: darkMode ? '#ccc' : undefined }}
label={{
value: 'Total Hours',
angle: -90,
position: 'insideLeft',
offset: -50,
style: { fontSize: 18, fill: darkMode ? '#ccc' : undefined },
}}
/>

<Line
type="linear"
dataKey="totalHours"
stroke="#328D1B"
strokeWidth={4}
dot={renderCustomDot}
strokeLinecap="round"
/>
<Tooltip content={renderCustomTooltip} />
</LineChart>
</ResponsiveContainer>
</div>
)}
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@
}

.chartContainer {
display: grid;
justify-content: center;
text-align: center;
padding: 10px;
position: relative;
width: 100%;
padding: 10px 0 15px;
margin-top: 20px;
margin-bottom: 15px;

display: flex;
flex-direction: column;
align-items: stretch;
text-align: left;
}

.customDateRange {
Expand All @@ -32,7 +34,7 @@
display: flex;
gap: 10px;
align-items: center;
justify-content: center;
justify-content: flex-start;
}

.dateFilterContainer > select {
Expand Down
Loading