Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chris_spinning_wheel_date_change_reports #2298

Merged
merged 4 commits into from
Jun 29, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
185 changes: 84 additions & 101 deletions src/components/Reports/TotalReport/TotalPeopleReport.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Link } from 'react-router-dom';
import { useEffect, useState } from 'react';
import { useEffect, useState, useMemo, useCallback } from 'react';
import { ENDPOINTS } from 'utils/URL';
import axios from 'axios';
import './TotalReport.css';
Expand All @@ -11,7 +11,7 @@ import Loading from '../../common/Loading';
function TotalPeopleReport(props) {
const { startDate, endDate, userProfiles, darkMode } = props;
const [dataLoading, setDataLoading] = useState(true);
const [dataRefresh, setDataRefresh] = useState(false);
const [dataReady, setDataReady] = useState(false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps it's better to name the state variable as specific as possible for better code readability and user experience.
For example, instead of dataReady , we could have totalPeopleReportDataReady or something along the lines of that. This would effectively convey the proper idea behind the state variable.

const [showTotalPeopleTable, setShowTotalPeopleTable] = useState(false);
const [allTimeEntries, setAllTimeEntries] = useState([]);
const [allPeople, setAllPeople] = useState([]);
Expand All @@ -20,12 +20,12 @@ function TotalPeopleReport(props) {
const [showMonthly, setShowMonthly] = useState(false);
const [showYearly, setShowYearly] = useState(false);

const fromDate = startDate.toLocaleDateString('en-CA');
const toDate = endDate.toLocaleDateString('en-CA');
const fromDate = useMemo(() => startDate.toLocaleDateString('en-CA'), [startDate]);
const toDate = useMemo(() => endDate.toLocaleDateString('en-CA'), [endDate]);

const userList = userProfiles.map(user => user._id);
const userList = useMemo(() => userProfiles.map(user => user._id), [userProfiles]);

const loadTimeEntriesForPeriod = async (controller) => {
const loadTimeEntriesForPeriod = useCallback(async (controller) => {
try {
const url = ENDPOINTS.TIME_ENTRIES_REPORTS;
const res = await axios.post(url, { users: userList, fromDate, toDate }, { signal: controller.signal });
Expand All @@ -44,10 +44,9 @@ function TotalPeopleReport(props) {
console.error("API error:", err.message);
}
}
};

}, [fromDate, toDate, userList]);

const sumByUser = (objectArray, property) => {
const sumByUser = useCallback((objectArray, property) => {
return objectArray.reduce((acc, obj) => {
const key = obj[property];
if (!acc[key]) {
Expand All @@ -67,16 +66,15 @@ function TotalPeopleReport(props) {
acc[key].minutes += Number(obj.minutes);
return acc;
}, {});
};
}, []);

const groupByTimeRange = (objectArray, timeRange) => {
const groupByTimeRange = useCallback((objectArray, timeRange) => {
let range = 0;
if (timeRange === 'month') {
range = 7;
} else if (timeRange === 'year') {
range = 4;
} else {
// eslint-disable-next-line no-console
console.log('The time range should be month or year.');
}
return objectArray.reduce((acc, obj) => {
Expand All @@ -86,68 +84,62 @@ function TotalPeopleReport(props) {
acc[key] = month;
return acc;
}, {});
};
}, []);

const filterTenHourUser = userTimeList => {
const filteredUsers = [];
userTimeList.forEach(element => {
const allTimeLogged = element.hours + element.minutes / 60.0;
const allTangibleTimeLogged = element.tangibleHours + element.tangibleMinutes / 60.0;
if (allTimeLogged >= 10) {
const matchedUser = userProfiles.filter(user => user._id === element.userId)[0];
const filterTenHourUser = useCallback(userTimeList => {
return userTimeList
.filter(element => {
const allTimeLogged = element.hours + element.minutes / 60.0;
return allTimeLogged >= 10;
})
.map(element => {
const matchedUser = userProfiles.find(user => user._id === element.userId);
if (matchedUser) {
filteredUsers.push({
const allTangibleTimeLogged = element.tangibleHours + element.tangibleMinutes / 60.0;
return {
userId: element.userId,
firstName: matchedUser.firstName,
lastName: matchedUser.lastName,
totalTime: allTimeLogged.toFixed(2),
totalTime: (element.hours + element.minutes / 60.0).toFixed(2),
tangibleTime: allTangibleTimeLogged.toFixed(2),
});
};
}
}
});
return filteredUsers;
};
return null;
})
.filter(Boolean);
}, [userProfiles]);

const summaryOfTimeRange = timeRange => {
const summaryOfTimeRange = useCallback(timeRange => {
const groupedEntries = Object.entries(groupByTimeRange(allTimeEntries, timeRange));
const summaryOfTime = [];
groupedEntries.forEach(element => {
const groupedUsersOfTime = Object.values(sumByUser(element[1], 'userId'));
return groupedEntries.map(([key, entries]) => {
const groupedUsersOfTime = Object.values(sumByUser(entries, 'userId'));
const contributedUsersOfTime = filterTenHourUser(groupedUsersOfTime);
summaryOfTime.push({ timeRange: element[0], usersOfTime: contributedUsersOfTime });
return { timeRange: key, usersOfTime: contributedUsersOfTime };
});
return summaryOfTime;
};
}, [allTimeEntries, groupByTimeRange, sumByUser, filterTenHourUser]);


const generateBarData = (groupedDate, isYear = false) => {
const generateBarData = useCallback((groupedDate, isYear = false) => {
if (isYear) {
const startMonth = startDate.getMonth();
const endMonth = endDate.getMonth();
const sumData = groupedDate.map(range => {
return {
label: range.timeRange,
value: range.usersOfTime.length,
months: 12,
};
});
const sumData = groupedDate.map(range => ({
label: range.timeRange,
value: range.usersOfTime.length,
months: 12,
}));
if (sumData.length > 1) {
sumData[0].months = 12 - startMonth;
sumData[sumData.length - 1].months = endMonth + 1;
}
return sumData;
}
const sumData = groupedDate.map(range => {
return {
label: range.timeRange,
value: range.usersOfTime.length,
};
});
return sumData;
};
return groupedDate.map(range => ({
label: range.timeRange,
value: range.usersOfTime.length,
}));
}, [startDate, endDate]);

const checkPeriodForSummary = () => {
const checkPeriodForSummary = useCallback(() => {
const oneMonth = 1000 * 60 * 60 * 24 * 31;
const diffDate = endDate - startDate;
if (diffDate > oneMonth) {
Expand All @@ -160,74 +152,64 @@ function TotalPeopleReport(props) {
setShowYearly(true);
}
}
};
}, [endDate, startDate, generateBarData, summaryOfTimeRange]);

useEffect(() => {
setDataReady(false);
const controller = new AbortController();
loadTimeEntriesForPeriod(controller).then(() => {
setDataLoading(false);
setDataRefresh(true);
setDataReady(true);
});
return () => controller.abort();
}, [startDate, endDate]);
}, [loadTimeEntriesForPeriod, startDate, endDate]);

useEffect(() => {
if (!dataLoading && dataRefresh) {
if (!dataLoading && dataReady) {
setShowMonthly(false);
setShowYearly(false);
const groupedUsers = Object.values(sumByUser(allTimeEntries, 'userId'));
const contributedUsers = filterTenHourUser(groupedUsers);
setAllPeople(contributedUsers);
checkPeriodForSummary();
setDataRefresh(false);
}
}, [dataRefresh]);
}, [dataLoading, dataReady, sumByUser, filterTenHourUser, allTimeEntries, checkPeriodForSummary]);

const onClickTotalPeopleDetail = () => {
const showDetail = showTotalPeopleTable;
setShowTotalPeopleTable(!showDetail);
setShowTotalPeopleTable(prevState => !prevState);
};

const totalPeopleTable = totalPeople => {
let PeopleList = [];
if (totalPeople.length > 0) {
PeopleList = totalPeople
.sort((a, b) => a.firstName.localeCompare(b.firstName))
.map((person, index) => (
<tr className="teams__tr" id={`tr_${person.userId}`} key={person.userId}>
<th className="teams__order--input" scope="row">
<div>{index + 1}</div>
</th>
<td>
<Link to={`/userProfile/${person.userId}`} className={darkMode ? 'text-light' : ''}>
{person.firstName} {person.lastName}
</Link>
</td>
<td>{person.totalTime}</td>
</tr>
));
}

return (
<table className="table table-bordered table-responsive-sm">
<thead>
<tr>
<th scope="col" id="projects__order">
#
</th>
<th scope="col">Person Name</th>
<th scope="col">Total Logged Time (Hrs) </th>
</tr>
</thead>
<tbody>{PeopleList}</tbody>
</table>
);
};
const totalPeopleTable = totalPeople => (
<table className="table table-bordered table-responsive-sm">
<thead>
<tr>
<th scope="col" id="projects__order">#</th>
<th scope="col">Person Name</th>
<th scope="col">Total Logged Time (Hrs)</th>
</tr>
</thead>
<tbody>
{totalPeople
.sort((a, b) => a.firstName.localeCompare(b.firstName))
.map((person, index) => (
<tr className="teams__tr" id={`tr_${person.userId}`} key={person.userId}>
<th className="teams__order--input" scope="row">
<div>{index + 1}</div>
</th>
<td>
<Link to={`/userProfile/${person.userId}`} className={darkMode ? 'text-light' : ''}>
{person.firstName} {person.lastName}
</Link>
</td>
<td>{person.totalTime}</td>
</tr>
))}
</tbody>
</table>
);

const totalPeopleInfo = totalPeople => {
const totalTangibleTime = totalPeople.reduce((acc, obj) => {
return acc + Number(obj.tangibleTime);
}, 0);
const totalTangibleTime = totalPeople.reduce((acc, obj) => acc + Number(obj.tangibleTime), 0);
return (
<div className={`total-container ${darkMode ? 'bg-yinmn-blue text-light' : ''}`}>
<div className={`total-title ${darkMode ? 'text-azure' : ''}`}>Total People Report</div>
Expand All @@ -252,7 +234,7 @@ function TotalPeopleReport(props) {
</div>
{allPeople.length ? (
<div className="total-detail">
<Button onClick={() => onClickTotalPeopleDetail()}>
<Button onClick={onClickTotalPeopleDetail}>
{showTotalPeopleTable ? 'Hide Details' : 'Show Details'}
</Button>
<i
Expand All @@ -275,8 +257,8 @@ function TotalPeopleReport(props) {

return (
<div>
{dataLoading ? (
<Loading align="center" darkMode={darkMode}/>
{!dataReady ? (
<Loading align="center" darkMode={darkMode} />
) : (
<div>
<div>{totalPeopleInfo(allPeople)}</div>
Expand All @@ -286,4 +268,5 @@ function TotalPeopleReport(props) {
</div>
);
}

export default TotalPeopleReport;
Loading
Loading