Skip to content
Merged
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
11 changes: 9 additions & 2 deletions src/components/TotalOrgSummary/TotalOrgSummary.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,9 @@ function TotalOrgSummary(props) {
await new Promise(resolve => setTimeout(resolve, 5000));

// 3. Replace Chart.js canvas elements with images in the live DOM.
const chartCanvases = document.querySelectorAll('.volunteer-status-chart canvas');
const chartCanvases = document.querySelectorAll(
'[data-chart="volunteer-status"] canvas, [data-chart="mentor-status"] canvas',
);
const originalCanvases = [];
chartCanvases.forEach(canvasElem => {
try {
Expand Down Expand Up @@ -673,7 +675,11 @@ ${
</Col>
<Col lg={{ size: 6 }}>
<div
className={clsx(styles.componentContainer, styles.componentBorder)}
className={clsx(
styles.componentContainer,
styles.componentBorder,
styles.componentBorderLoose,
)}
data-pdf-block
>
<div
Expand All @@ -688,6 +694,7 @@ ${
<VolunteerStatusChart
isLoading={isLoading}
volunteerNumberStats={volunteerStats?.volunteerNumberStats}
mentorNumberStats={volunteerStats?.mentorNumberStats}
comparisonType={selectedComparison}
/>
</div>
Expand Down
35 changes: 5 additions & 30 deletions src/components/TotalOrgSummary/TotalOrgSummary.module.css
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
/* Chart labels stay dark in dark mode for readability against light label chips */
.containerTotalOrgWrapper:global(.bg-oxford-blue) .componentContainer .recharts-wrapper text,
.containerTotalOrgWrapper:global(.bg-oxford-blue) .componentContainer .recharts-wrapper tspan {
fill: #000 !important;
color: #000 !important;
text-shadow: 1px 1px 3px rgba(0,0,0,0.25), 0 0 2px #fff;
}
/* Chart title stays white, but chart numbers/labels inside the donut graph are black for better contrast */
.containerTotalOrgWrapper:global(.bg-oxford-blue) .componentContainer .recharts-wrapper text,
.containerTotalOrgWrapper:global(.bg-oxford-blue) .componentContainer .recharts-wrapper tspan {
fill: #000 !important;
color: #000 !important;
}
/* Chart and graph titles/text should be white in dark mode for visibility */
.containerTotalOrgWrapper:global(.bg-oxford-blue) .componentContainer h3,
.containerTotalOrgWrapper:global(.bg-oxford-blue) .componentContainer p,
Expand Down Expand Up @@ -73,11 +68,6 @@
box-shadow: 0 4px 12px rgba(0, 123, 255, 0.4) !important;
}

.containerTotalOrgWrapper:global(.bg-oxford-blue) .componentBorder {
background-color: #1c2541 !important;
border: none !important;
}

.containerTotalOrgWrapper:global(.bg-oxford-blue) .componentContainer {
background-color: #1c2541 !important;
border: none !important;
Expand Down Expand Up @@ -279,25 +269,6 @@
}

/* Dark mode dropdown consistency */
.containerTotalOrgWrapper:global(.bg-oxford-blue) .reportHeaderActions :global(.dropdown-toggle) {
background-color: #6f42c1 !important;
border-color: #6f42c1 !important;
}

.containerTotalOrgWrapper:global(.bg-oxford-blue) .reportHeaderActions :global(.dropdown-menu) {
background-color: #1c2541 !important;
border-color: #6f42c1 !important;
}

.containerTotalOrgWrapper:global(.bg-oxford-blue) .reportHeaderActions :global(.dropdown-item) {
background-color: #1c2541 !important;
color: #fff !important;
}

.containerTotalOrgWrapper:global(.bg-oxford-blue) .reportHeaderActions :global(.dropdown-item):hover {
background-color: #6f42c1 !important;
}

/* Component containers - Clean borderless design */
.componentContainer {
margin: 15px 0;
Expand All @@ -315,6 +286,10 @@
background-color: #fff;
overflow: hidden;
}

.componentBorderLoose {
overflow: visible;
}
.containerTotalOrgWrapper:global(.bg-oxford-blue) .componentBorder {
background-color: #1c2541 !important;
border: 1.5px solid #2f4157 !important;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import PropTypes from 'prop-types';
import { Doughnut } from 'react-chartjs-2';
import { Chart, ArcElement } from 'chart.js';
import styles from './MentorStatusPieChart.module.css';
import externalLabelGuidesPlugin from './externalLabelGuidesPlugin';

Chart.register(ArcElement);

function MentorStatusPieChart({
data: { totalMentors, percentageChange, data: mentorData },
comparisonType,
}) {
const chartData = {
labels: mentorData.map(item => item.label),
datasets: [
{
data: mentorData.map(item => item.value),
backgroundColor: ['#287D5A', '#2D9DA6', '#F26B38'],
borderWidth: 1,
},
],
};

const options = {
plugins: {
datalabels: {
display: false,
},
legend: {
display: false,
},
tooltip: {
enabled: false,
},
externalLabelGuides: {
offset: 20,
horizontalSpread: 32,
horizontalSpreadMap: { 0: 32, 1: 46, 2: 5 },
verticalOffsetMap: { 0: 34, 1: -20, 2: -46 },
sideMap: { 0: 1, 1: -1, 2: 1 },
total: totalMentors,
formatter: ({ value, percentage }) => [`${value}`, `(${percentage}%)`],
},
},
maintainAspectRatio: false,
cutout: '60%',
layout: {
padding: 20,
},
};

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

return (
<section className={styles.mentorStatusContainer} aria-label="Mentor Status Overview">
<div
className={styles.mentorStatusChart}
data-chart="mentor-status"
role="img"
aria-label="Mentor Status Pie Chart"
>

Check warning on line 61 in src/components/TotalOrgSummary/VolunteerStatus/MentorStatusPieChart.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=AZr3qxw5cqSqORs_HGk_&open=AZr3qxw5cqSqORs_HGk_&pullRequest=4138
<Doughnut data={chartData} options={options} plugins={[externalLabelGuidesPlugin]} />
<div className={styles.mentorStatusCenter}>
<h2 className={styles.mentorStatusHeading}>TOTAL MENTORS</h2>
<p className={styles.mentorCount}>{totalMentors}</p>
{comparisonType !== 'No Comparison' && (
<p
className={styles.mentorPercentageChange}
style={{ color: percentageChangeColor }}
aria-label={`Mentor percentage change: ${percentageChange}% ${comparisonType.toLowerCase()}`}
>
{percentageChange >= 0
? `+${percentageChange}% ${comparisonType.toUpperCase()}`
: `${percentageChange}% ${comparisonType.toUpperCase()}`}
</p>
)}
</div>
</div>
<div className={styles.mentorStatusLabels}>
{mentorData.map((item, index) => (
<div key={item.label} className={styles.mentorStatusLabel}>
<span
className={styles.mentorStatusColor}
style={{ backgroundColor: chartData.datasets[0].backgroundColor[index] }}
aria-hidden="true"
/>
<span>{item.label}</span>
</div>
))}
</div>
</section>
);
}

MentorStatusPieChart.propTypes = {
data: PropTypes.shape({
totalMentors: PropTypes.number.isRequired,
percentageChange: PropTypes.number.isRequired,
data: PropTypes.arrayOf(
PropTypes.shape({
label: PropTypes.string.isRequired,
value: PropTypes.number.isRequired,
}),
).isRequired,
}).isRequired,
comparisonType: PropTypes.string.isRequired,
};

export default MentorStatusPieChart;
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
.mentorStatusContainer {
margin-top: 24px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
width: 100%;
height: 100%;
gap: 12px;
}

.mentorStatusChart {
position: relative;
width: min(320px, 100%);
max-width: 320px;
aspect-ratio: 1 / 1;
overflow: visible;
}

.mentorStatusCenter {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
font-size: 14px;
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
}

.mentorStatusHeading {
color: #828282;
font-size: 1.2rem;
letter-spacing: 0.5px;
text-transform: uppercase;
transform: translateY(6px);
width: 100%;
text-align: center;
}

.mentorCount {
color: #6c6c6c;
font-size: 1.8rem;
font-weight: 800;
line-height: 1.18;
margin-top: -10px;
}

.mentorPercentageChange {
font-weight: 600;
}

.mentorStatusLabels {
display: flex;
justify-content: center;
align-items: center;
gap: 16px;
margin-top: 48px;
margin-bottom: 24px;
flex-wrap: nowrap;
padding: 0 20px;
width: max-content;
max-width: 100%;
box-sizing: border-box;
}

.mentorStatusLabel {
display: flex;
align-items: center;
gap: 6px;
font-size: 0.875rem;
white-space: nowrap;
}

.mentorStatusColor {
display: inline-block;
width: 12px;
height: 12px;
border-radius: 2px;
}

:global(.bg-oxford-blue) .mentorStatusHeading {
color: #f1f5ff;
}

:global(.bg-oxford-blue) .mentorCount {
color: #ffffff;
}

@media (max-width: 768px) {
.mentorStatusChart {
width: min(280px, 100%);
}

.mentorStatusLabels {
gap: 12px;
}
}

@media (min-width: 768px) {
.mentorStatusChart {
max-width: 280px;
}
}
Loading
Loading