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 @@ -67,6 +67,7 @@ export default function AnniversaryCelebrated({ isLoading, data, darkMode }) {
<SiGmail
size={30}
color="red"
className="anniversaryGmailIcon"
style={{ cursor: 'pointer', display: 'block' }}
onClick={() => handleEmailClick(email)}
/>
Expand Down Expand Up @@ -110,8 +111,36 @@ export default function AnniversaryCelebrated({ isLoading, data, darkMode }) {
const filterUsers = users =>
users.filter(u => `${u.firstName} ${u.lastName}`.toLowerCase().includes(search.toLowerCase()));

const searchInputStyle = {
margin: '10px 0',
padding: '5px 10px',
borderRadius: '5px',
border: darkMode ? '1px solid rgba(255, 255, 255, 0.25)' : '1px solid gray',
width: '60%',
backgroundColor: darkMode ? '#111827' : '#fff',
color: darkMode ? '#f8fafc' : '#111827',
WebkitTextFillColor: darkMode ? '#f8fafc' : '#111827',
};

return (
<div className="mt-3">
<style>
{`
#anniversary-search::placeholder {
color: ${darkMode ? 'rgba(248,250,252,0.75)' : 'rgba(17,24,39,0.6)'} !important;
}


.anniversaryGmailIcon {
color: #ea4335 !important;
fill: #ea4335 !important;
}

.anniversaryGmailIcon path {
fill: #ea4335 !important;
}
`}
</style>
{/* Comparison percentages with counts */}
{hasComparisonData && (
<span
Expand Down Expand Up @@ -150,17 +179,12 @@ export default function AnniversaryCelebrated({ isLoading, data, darkMode }) {
{/* Search + Export Controls */}
<div className="d-flex justify-content-between align-items-center mb-2">
<input
id="anniversary-search"
type="text"
placeholder="Search by name"
value={search}
onChange={e => setSearch(e.target.value)}
style={{
margin: '10px 0',
padding: '5px 10px',
borderRadius: '5px',
border: '1px solid gray',
width: '60%',
}}
style={searchInputStyle}
/>
<button onClick={exportData} className="btn btn-secondary">
Export Data
Expand Down
3 changes: 3 additions & 0 deletions src/components/TotalOrgSummary/DonutChart/DonutChart.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
size: 16,
},
formatter: value => {
if (totalCount === 0 || isNaN(totalCount) || !isFinite(totalCount)) {

Check warning on line 31 in src/components/TotalOrgSummary/DonutChart/DonutChart.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Prefer `Number.isNaN` over `isNaN`.

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0u1W2bseWqV-TzYnUI&open=AZ0u1W2bseWqV-TzYnUI&pullRequest=4694

Check warning on line 31 in src/components/TotalOrgSummary/DonutChart/DonutChart.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Prefer `Number.isFinite` over `isFinite`.

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0u1W2bseWqV-TzYnUJ&open=AZ0u1W2bseWqV-TzYnUJ&pullRequest=4694
return `${value}`;
}
const percentage = ((value / totalCount) * 100).toFixed(0);
return `${value}\n(${percentage}%)`;
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import TinyBarChart from '../TinyBarChart';
import Loading from '../../common/Loading';

export default function HoursCompletedBarChart({ isLoading, data, darkMode }) {

Check failure on line 5 in src/components/TotalOrgSummary/HoursCompleted/HoursCompletedBarChart.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this function to reduce its Cognitive Complexity from 17 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ136XLt6AnbEIDJnWUM&open=AZ136XLt6AnbEIDJnWUM&pullRequest=4694
const initialCardSize = () => {
if (window.innerWidth <= 680) {
return { height: '240px' };
Expand Down Expand Up @@ -140,6 +140,22 @@
);
};

// for top right positioning of the projects box
const projectsBoxPosition =
cardSize.height === '300px'
? { top: '28%', right: '10%' }
: cardSize.height === '548px'
? { top: '30%', right: '8%' }
: { top: '30%', right: '6%' };

Check warning on line 149 in src/components/TotalOrgSummary/HoursCompleted/HoursCompletedBarChart.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Extract this nested ternary operation into an independent statement.

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0uGLo9lpSFCu4-DtH3&open=AZ0uGLo9lpSFCu4-DtH3&pullRequest=4694

const projectsTextStyle = {
color: darkMode ? '#ffffff' : '#222222',
};

const projectsMutedTextStyle = {
color: darkMode ? '#d1d5db' : '#666666',
};

return (
<div
style={{
Expand All @@ -155,29 +171,40 @@
<div
style={{
position: 'absolute',
top: '40%',
left: '65%',
...projectsBoxPosition,
left: 'auto',
transform: 'translateY(-50%)',
zIndex: 10,
background: 'white',
background: darkMode ? '#1f2937' : '#ffffff',
borderRadius: 4,
padding: 8,
boxShadow: '0 2px 6px rgba(0,0,0,0.15)',
border: '1px solid #eee',
minWidth: 130,
minHeight: 65,
padding: 4,
boxShadow: darkMode ? '0 2px 6px rgba(0,0,0,0.35)' : '0 2px 6px rgba(0,0,0,0.15)',
border: darkMode ? '1px solid rgba(255,255,255,0.15)' : '1px solid #eee',
minWidth: 105,
minHeight: 45,
display: 'grid',
justifyItems: 'center',
gap: 2,
isolation: 'isolate',
}}
>
<div style={{ color: '#444', fontWeight: 'bold', fontSize: 15 }}>Projects</div>
<div style={{ color: '#222', fontWeight: 'bold', fontSize: 14 }}>
<div style={{ ...projectsTextStyle, fontWeight: 'bold', fontSize: 15 }}>Projects</div>
<div style={{ ...projectsTextStyle, fontWeight: 'bold', fontSize: 14 }}>
{projectBarInfo.amount}
</div>
<div style={{ color: '#666', fontSize: 10 }}>({projectBarInfo.percentage})</div>

<div style={{ ...projectsMutedTextStyle, fontSize: 10 }}>({projectBarInfo.percentage})</div>

{projectBarInfo.ifcompare && (
<div style={{ color: projectBarInfo.fontcolor, fontSize: 10, fontWeight: 'bold' }}>
<div
style={{
...projectsTextStyle,
color: darkMode ? 'lightgreen' : 'green',

fontSize: 10,
fontWeight: 'bold',
}}
>
{projectBarInfo.change}
</div>
)}
Expand Down Expand Up @@ -223,7 +250,6 @@
chartData={chartData.filter(item => item.name === 'Tasks')}
maxY={maxY}
tickInterval={tickInterval}
// renderCustomizedLabel={renderCustomizedLabel}
darkMode={darkMode}
yAxisLabel="Hours"
/>
Expand Down
7 changes: 0 additions & 7 deletions src/components/TotalOrgSummary/TeamStats/TeamStats.css

This file was deleted.

108 changes: 81 additions & 27 deletions src/components/TotalOrgSummary/TeamStats/TeamStats.jsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,49 @@
import { useState, useEffect } from 'react';
import { useEffect, useRef, useState } from 'react';
import { ENDPOINTS } from '~/utils/URL';
import axios from 'axios';
import Loading from '~/components/common/Loading';
import TeamStatsBarChart from './TeamStatsBarChart';
import './TeamStats.css';
import styles from './TeamStats.module.css';

const activeMembersMinimumDropDownOptions = [2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30];

function TeamStats({ isLoading, usersInTeamStats, endDate }) {
function TeamStats({ isLoading, usersInTeamStats, endDate, darkMode }) {

Check warning on line 10 in src/components/TotalOrgSummary/TeamStats/TeamStats.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'darkMode' is missing in props validation

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0uGLjNlpSFCu4-DtH0&open=AZ0uGLjNlpSFCu4-DtH0&pullRequest=4694
const [activeMembersMinimum, setActiveMembersMinimum] = useState(
activeMembersMinimumDropDownOptions[0],
);
const [teamsWithActiveMembers, setTeamsWithActiveMembers] = useState(null);
const [teamsStatsFetchingError, setTeamsStatsFetchingError] = useState(null);
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const dropdownRef = useRef(null);

const isDarkMode =
typeof darkMode === 'boolean' ? darkMode : document.body.classList.contains('dark-mode');

useEffect(() => {
const fetchTeamsData = async () => {
try {
const url = ENDPOINTS.VOLUNTEER_ROLES_TEAM_STATS(endDate, activeMembersMinimum);
// NEED TO ABSTRACT THIS TO ITS OWN REDUX REDUCER
const response = await axios.get(url);
const { data } = response;
setTeamsWithActiveMembers(data.teamsWithActiveMembers);
} catch (error) {
setTeamsStatsFetchingError(error);
}
};

fetchTeamsData();
}, [activeMembersMinimum]);
}, [activeMembersMinimum, endDate]);

useEffect(() => {
function handleClickOutside(event) {
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
setIsDropdownOpen(false);
}
}

document.addEventListener('mousedown', handleClickOutside);
return () => document.removeEventListener('mousedown', handleClickOutside);
}, []);

if (isLoading) {
return (
Expand Down Expand Up @@ -60,38 +76,76 @@
},
];

function handleActiveMembersMinimumChange(event) {
const selectedActiveMembersMinimum = event.target.value;
if (!selectedActiveMembersMinimum) return;
setActiveMembersMinimum(selectedActiveMembersMinimum);
const buttonStyle = {
backgroundColor: isDarkMode ? '#111827' : '#ffffff',
color: isDarkMode ? '#f8fafc' : '#111827',
border: isDarkMode ? '1px solid rgba(255, 255, 255, 0.20)' : '1px solid #c7c7c7',
};

const menuStyle = {
backgroundColor: isDarkMode ? '#111827' : '#ffffff',
color: isDarkMode ? '#f8fafc' : '#111827',
border: isDarkMode ? '1px solid rgba(255, 255, 255, 0.20)' : '1px solid #c7c7c7',
};

function handleOptionSelect(value) {
setActiveMembersMinimum(value);
setIsDropdownOpen(false);
}

return (
<div>
<TeamStatsBarChart data={data} yAxisLabel="name" />
{teamsWithActiveMembers && (
<div className="team-stats-active-members">
<div className="team-stats-bar-chart-summary">
<span>
<div className={styles.teamStatsActiveMembers}>
<div className={styles.teamStatsBarChartSummary}>
<div className={styles.teamStatsSummaryText}>
{`${teamsWithActiveMembers.count} ${
teamsWithActiveMembers.count === 1 ? 'team' : 'teams'
} with`}
<select
onChange={handleActiveMembersMinimumChange}
value={activeMembersMinimum}
className="team-stats-active-members-dropdown"
>
{activeMembersMinimumDropDownOptions.map(activeMembersMinimumOption => (
<option
key={`${activeMembersMinimumOption}-dropdown`}
value={activeMembersMinimumOption}
>
{activeMembersMinimumOption}
</option>
))}
</select>
<div ref={dropdownRef} className={styles.customDropdown}>
<button
type="button"
className={styles.dropdownButton}
style={buttonStyle}
onClick={() => setIsDropdownOpen(prev => !prev)}
>
<span>{activeMembersMinimum}</span>
<span
className={`${styles.dropdownArrow} ${
isDropdownOpen ? styles.dropdownArrowOpen : ''
}`}
/>
</button>

{isDropdownOpen && (
<ul className={styles.dropdownMenu} style={menuStyle}>
{activeMembersMinimumDropDownOptions.map(option => (
<li key={option}>
<button
type="button"
className={styles.dropdownItem}
style={{
color: isDarkMode ? '#f8fafc' : '#111827',
backgroundColor:
option === activeMembersMinimum
? isDarkMode
? 'rgba(255, 255, 255, 0.10)'
: '#f3f4f6'

Check warning on line 134 in src/components/TotalOrgSummary/TeamStats/TeamStats.jsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Extract this nested ternary operation into an independent statement.

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ0ydd4QbMJlKzboB1mz&open=AZ0ydd4QbMJlKzboB1mz&pullRequest=4694
: 'transparent',
fontWeight: option === activeMembersMinimum ? 700 : 400,
}}
onClick={() => handleOptionSelect(option)}
>
{option}
</button>
</li>
))}
</ul>
)}
</div>
+ active members
</span>
</div>
</div>
</div>
)}
Expand Down
Loading
Loading