From d334237965f3bab48c07a7fbe79c0d8728ef6b55 Mon Sep 17 00:00:00 2001 From: ivenyao Date: Thu, 2 May 2024 16:45:27 -0700 Subject: [PATCH 1/6] use multi-select component for the filter layout --- .../TeamMemberTasks/TeamMemberTasks.jsx | 45 ++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/src/components/TeamMemberTasks/TeamMemberTasks.jsx b/src/components/TeamMemberTasks/TeamMemberTasks.jsx index 8cbb8d6a4d..6aa52c5d12 100644 --- a/src/components/TeamMemberTasks/TeamMemberTasks.jsx +++ b/src/components/TeamMemberTasks/TeamMemberTasks.jsx @@ -1,6 +1,6 @@ import { Fragment } from 'react'; import { faClock } from '@fortawesome/free-solid-svg-icons'; -import { Table } from 'reactstrap'; +import { Table, Row, Col } from 'reactstrap'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { fetchTeamMembersTask, deleteTaskNotification } from 'actions/task'; import React, { useEffect, useState, useCallback } from 'react'; @@ -20,6 +20,7 @@ import { toast } from 'react-toastify'; // import InfiniteScroll from 'react-infinite-scroller'; import { getAllTimeOffRequests } from '../../actions/timeOffRequestAction'; import { fetchAllFollowUps } from '../../actions/followUpActions'; +import { MultiSelect } from 'react-multi-select-component'; const TeamMemberTasks = React.memo(props => { const darkMode = useSelector(state => state.theme.darkMode); @@ -43,6 +44,12 @@ const TeamMemberTasks = React.memo(props => { const [showWhoHasTimeOff, setShowWhoHasTimeOff] = useState(true); const userOnTimeOff = useSelector(state => state.timeOffRequests.onTimeOff); const userGoingOnTimeOff = useSelector(state => state.timeOffRequests.goingOnTimeOff); + const [teamNames, setTeamNames] = useState([]); + const [teamCodes, setTeamCodes] = useState([]); + const [colorOptions, setColorOptions] = useState([]); + const [selectedTeamNames, setSelectedTeamNames] = useState([]); + const [selectedCodes, setSelectedCodes] = useState([]); + const [selectedColors, setSelectedColors] = useState([]); const dispatch = useDispatch(); @@ -181,6 +188,7 @@ const TeamMemberTasks = React.memo(props => { const renderTeamsList = async () => { if (usersWithTasks.length > 0) { + console.log(usersWithTasks); //sort all users by their name usersWithTasks.sort((a, b) => (a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1)); //find currentUser @@ -318,6 +326,41 @@ const TeamMemberTasks = React.memo(props => { taskModalOption={taskModalOption} /> )} + + + Select Team + { + // this.handleSelectCodeChange(e); + }} + /> + + + Select Team Code + { + // this.handleSelectCodeChange(e); + }} + /> + + + Select Color + { + // this.handleSelectColorChange(e); + }} + /> + +
From eecfb449efba7651f346f49c894aa80e9fece4d9 Mon Sep 17 00:00:00 2001 From: ivenyao Date: Thu, 2 May 2024 21:47:22 -0700 Subject: [PATCH 2/6] update teamCodes and color options and filter feature --- .../TeamMemberTasks/TeamMemberTasks.jsx | 87 +++++++++++++++++-- 1 file changed, 81 insertions(+), 6 deletions(-) diff --git a/src/components/TeamMemberTasks/TeamMemberTasks.jsx b/src/components/TeamMemberTasks/TeamMemberTasks.jsx index 6aa52c5d12..115b4b6a8d 100644 --- a/src/components/TeamMemberTasks/TeamMemberTasks.jsx +++ b/src/components/TeamMemberTasks/TeamMemberTasks.jsx @@ -46,7 +46,7 @@ const TeamMemberTasks = React.memo(props => { const userGoingOnTimeOff = useSelector(state => state.timeOffRequests.goingOnTimeOff); const [teamNames, setTeamNames] = useState([]); const [teamCodes, setTeamCodes] = useState([]); - const [colorOptions, setColorOptions] = useState([]); + const [colors, setColors] = useState([]); const [selectedTeamNames, setSelectedTeamNames] = useState([]); const [selectedCodes, setSelectedCodes] = useState([]); const [selectedColors, setSelectedColors] = useState([]); @@ -188,7 +188,6 @@ const TeamMemberTasks = React.memo(props => { const renderTeamsList = async () => { if (usersWithTasks.length > 0) { - console.log(usersWithTasks); //sort all users by their name usersWithTasks.sort((a, b) => (a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1)); //find currentUser @@ -202,6 +201,54 @@ const TeamMemberTasks = React.memo(props => { } }; + const renderFilters = () => { + const teamGroup = {}; + const teamCodeGroup = {}; + const colorGroup = {}; + const teamOptions = []; + const teamCodeOptions = []; + const colorOptions = []; + + if(usersWithTasks.length > 0) { + console.log(usersWithTasks); + usersWithTasks.forEach(user => { + const code = user.teamCode || 'noCodeLabel'; + const color = user.weeklySummaryOption; + + if (teamCodeGroup[code]) { + teamCodeGroup[code].push(user.personId); + } else { + teamCodeGroup[code] = [user.personId]; + } + + if (colorGroup[color]) { + colorGroup[color].push(user.personId); + } else { + colorGroup[color] = [user.personId]; + } + }); + + Object.keys(teamCodeGroup).forEach(code => { + if (code !== 'noCodeLabel') { + teamCodeOptions.push({ + value: code, + label: `${code} (${teamCodeGroup[code].length})` + }); + } + }); + + Object.keys(colorGroup).forEach(color => { + colorOptions.push({ + value: color, + label: `${color} (${colorGroup[color].length})` + }) + }); + + setTeamCodes(teamCodeOptions); + setColors(colorOptions); + } + } + useEffect(() => { // TeamMemberTasks is only imported in TimeLog component, in which userId is already definitive const initialFetching = async () => { @@ -219,6 +266,7 @@ const TeamMemberTasks = React.memo(props => { useEffect(() => { if (!isLoading) { renderTeamsList(); + renderFilters(); closeMarkAsDone(); } }, [usersWithTasks]); @@ -231,6 +279,33 @@ const TeamMemberTasks = React.memo(props => { setShowWhoHasTimeOff(prev => !prev); }; + const handleSelectCodeChange = event => { + setSelectedCodes(event); + } + + const handleSelectColorChange = event => { + setSelectedColors(event); + } + + const filterByUserFeatures = (user) => { + if(selectedTeamNames.length === 0 && selectedCodes.length === 0 && selectedColors.length === 0) return true; + + return filterByTeamCodes(user.teamCode) || filterByColors(user.weeklySummaryOption); + } + + const filterByTeamNames = (name) => { + return selectedTeamNames.some(option => option.value === name); + } + + const filterByTeamCodes = (code) => { + return selectedCodes.some(option => option.value === code); + } + + const filterByColors = (color) => { + return selectedColors.some(option => option.value === color); + } + + return (
@@ -345,7 +420,7 @@ const TeamMemberTasks = React.memo(props => { options={teamCodes} value={selectedCodes} onChange={e => { - // this.handleSelectCodeChange(e); + handleSelectCodeChange(e); }} /> @@ -353,10 +428,10 @@ const TeamMemberTasks = React.memo(props => { Select Color { - // this.handleSelectColorChange(e); + handleSelectColorChange(e); }} /> @@ -413,7 +488,7 @@ const TeamMemberTasks = React.memo(props => { {isLoading ? ( ) : ( - teamList.map(user => { + teamList.filter((user) => filterByUserFeatures(user)).map(user => { if (!isTimeFilterActive) { return ( Date: Fri, 3 May 2024 17:21:36 -0700 Subject: [PATCH 3/6] update TeamMemberTasks, render teamName options, and finish filter functions --- .../TeamMemberTasks/TeamMemberTasks.jsx | 45 +++++++++++++++---- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/src/components/TeamMemberTasks/TeamMemberTasks.jsx b/src/components/TeamMemberTasks/TeamMemberTasks.jsx index 115b4b6a8d..5afce09e98 100644 --- a/src/components/TeamMemberTasks/TeamMemberTasks.jsx +++ b/src/components/TeamMemberTasks/TeamMemberTasks.jsx @@ -212,8 +212,17 @@ const TeamMemberTasks = React.memo(props => { if(usersWithTasks.length > 0) { console.log(usersWithTasks); usersWithTasks.forEach(user => { + const teamNames = user.teams.map(team => team.teamName); const code = user.teamCode || 'noCodeLabel'; - const color = user.weeklySummaryOption; + const color = user.weeklySummaryOption || 'noColorLabel'; + + teamNames.forEach(name => { + if(teamGroup[name]) { + teamGroup[name].push(user.personId); + } else { + teamGroup[name] = [user.personId]; + } + }); if (teamCodeGroup[code]) { teamCodeGroup[code].push(user.personId); @@ -228,6 +237,13 @@ const TeamMemberTasks = React.memo(props => { } }); + Object.keys(teamGroup).forEach(name => { + teamOptions.push({ + value: name, + label: `${name} (${teamGroup[name].length})` + }); + }) + Object.keys(teamCodeGroup).forEach(code => { if (code !== 'noCodeLabel') { teamCodeOptions.push({ @@ -238,12 +254,15 @@ const TeamMemberTasks = React.memo(props => { }); Object.keys(colorGroup).forEach(color => { - colorOptions.push({ - value: color, - label: `${color} (${colorGroup[color].length})` - }) + if (color !== 'noColorLabel') { + colorOptions.push({ + value: color, + label: `${color} (${colorGroup[color].length})` + }); + } }); + setTeamNames(teamOptions); setTeamCodes(teamCodeOptions); setColors(colorOptions); } @@ -279,6 +298,10 @@ const TeamMemberTasks = React.memo(props => { setShowWhoHasTimeOff(prev => !prev); }; + const handleSelectTeamNames = event => { + setSelectedTeamNames(event); + } + const handleSelectCodeChange = event => { setSelectedCodes(event); } @@ -290,10 +313,16 @@ const TeamMemberTasks = React.memo(props => { const filterByUserFeatures = (user) => { if(selectedTeamNames.length === 0 && selectedCodes.length === 0 && selectedColors.length === 0) return true; - return filterByTeamCodes(user.teamCode) || filterByColors(user.weeklySummaryOption); + return filterByTeamCodes(user.teamCode) || filterByColors(user.weeklySummaryOption) || filterByTeams(user.teams); + } + + const filterByTeams = (teams) => { + let match = false; + teams.forEach(team => match = match || filterByTeamName(team.teamName)); + return match; } - const filterByTeamNames = (name) => { + const filterByTeamName = (name) => { return selectedTeamNames.some(option => option.value === name); } @@ -409,7 +438,7 @@ const TeamMemberTasks = React.memo(props => { options={teamNames} value={selectedTeamNames} onChange={e => { - // this.handleSelectCodeChange(e); + handleSelectTeamNames(e); }} /> From a5365116f726e39f0680655aac0d155605360ac9 Mon Sep 17 00:00:00 2001 From: ivenyao Date: Fri, 3 May 2024 22:18:28 -0700 Subject: [PATCH 4/6] sort the options by label in ascending order, only render filter for manager, mentor, admin and owner role --- .../TeamMemberTasks/TeamMemberTasks.jsx | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/components/TeamMemberTasks/TeamMemberTasks.jsx b/src/components/TeamMemberTasks/TeamMemberTasks.jsx index 5afce09e98..64dcd5d78c 100644 --- a/src/components/TeamMemberTasks/TeamMemberTasks.jsx +++ b/src/components/TeamMemberTasks/TeamMemberTasks.jsx @@ -237,14 +237,14 @@ const TeamMemberTasks = React.memo(props => { } }); - Object.keys(teamGroup).forEach(name => { + Object.keys(teamGroup).sort((a,b) => a.localeCompare(b)).forEach(name => { teamOptions.push({ value: name, label: `${name} (${teamGroup[name].length})` }); }) - Object.keys(teamCodeGroup).forEach(code => { + Object.keys(teamCodeGroup).sort((a,b) => a.localeCompare(b)).forEach(code => { if (code !== 'noCodeLabel') { teamCodeOptions.push({ value: code, @@ -253,7 +253,7 @@ const TeamMemberTasks = React.memo(props => { } }); - Object.keys(colorGroup).forEach(color => { + Object.keys(colorGroup).sort((a,b) => a.localeCompare(b)).forEach(color => { if (color !== 'noColorLabel') { colorOptions.push({ value: color, @@ -285,8 +285,11 @@ const TeamMemberTasks = React.memo(props => { useEffect(() => { if (!isLoading) { renderTeamsList(); - renderFilters(); closeMarkAsDone(); + console.log(displayUser.role); + if(['Administrator', 'Owner', 'Manager', 'Mentor'].some( role => role === displayUser.role)) { + renderFilters(); + } } }, [usersWithTasks]); @@ -430,7 +433,9 @@ const TeamMemberTasks = React.memo(props => { taskModalOption={taskModalOption} /> )} - + { + ['Administrator', 'Owner', 'Manager', 'Mentor'].some( role => role === displayUser.role) && +
Select Team { /> + }
From d5a3fe2e55899a75b3a3d866b9aa82bfc5673245 Mon Sep 17 00:00:00 2001 From: ivenyao Date: Wed, 8 May 2024 11:33:10 -0700 Subject: [PATCH 5/6] make filter logic be AND instead of OR --- src/components/TeamMemberTasks/TeamMemberTasks.jsx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/components/TeamMemberTasks/TeamMemberTasks.jsx b/src/components/TeamMemberTasks/TeamMemberTasks.jsx index 64dcd5d78c..e9cf2c7c6c 100644 --- a/src/components/TeamMemberTasks/TeamMemberTasks.jsx +++ b/src/components/TeamMemberTasks/TeamMemberTasks.jsx @@ -210,7 +210,6 @@ const TeamMemberTasks = React.memo(props => { const colorOptions = []; if(usersWithTasks.length > 0) { - console.log(usersWithTasks); usersWithTasks.forEach(user => { const teamNames = user.teams.map(team => team.teamName); const code = user.teamCode || 'noCodeLabel'; @@ -240,7 +239,7 @@ const TeamMemberTasks = React.memo(props => { Object.keys(teamGroup).sort((a,b) => a.localeCompare(b)).forEach(name => { teamOptions.push({ value: name, - label: `${name} (${teamGroup[name].length})` + label: `${name}` }); }) @@ -248,7 +247,7 @@ const TeamMemberTasks = React.memo(props => { if (code !== 'noCodeLabel') { teamCodeOptions.push({ value: code, - label: `${code} (${teamCodeGroup[code].length})` + label: `${code}` }); } }); @@ -257,7 +256,7 @@ const TeamMemberTasks = React.memo(props => { if (color !== 'noColorLabel') { colorOptions.push({ value: color, - label: `${color} (${colorGroup[color].length})` + label: `${color}` }); } }); @@ -286,7 +285,6 @@ const TeamMemberTasks = React.memo(props => { if (!isLoading) { renderTeamsList(); closeMarkAsDone(); - console.log(displayUser.role); if(['Administrator', 'Owner', 'Manager', 'Mentor'].some( role => role === displayUser.role)) { renderFilters(); } @@ -316,10 +314,11 @@ const TeamMemberTasks = React.memo(props => { const filterByUserFeatures = (user) => { if(selectedTeamNames.length === 0 && selectedCodes.length === 0 && selectedColors.length === 0) return true; - return filterByTeamCodes(user.teamCode) || filterByColors(user.weeklySummaryOption) || filterByTeams(user.teams); + return filterByTeamCodes(user.teamCode) && filterByColors(user.weeklySummaryOption) && filterByTeams(user.teams); } const filterByTeams = (teams) => { + if(selectedTeamNames.length === 0) return true; let match = false; teams.forEach(team => match = match || filterByTeamName(team.teamName)); return match; @@ -330,10 +329,12 @@ const TeamMemberTasks = React.memo(props => { } const filterByTeamCodes = (code) => { + if(selectedCodes.length === 0) return true; return selectedCodes.some(option => option.value === code); } const filterByColors = (color) => { + if(selectedColors.length === 0) return true; return selectedColors.some(option => option.value === color); } From 6a105c078397fb3ca5cfe453192d5a6dd6631a63 Mon Sep 17 00:00:00 2001 From: ivenyao Date: Fri, 10 May 2024 20:59:15 -0700 Subject: [PATCH 6/6] fix darkmode style --- src/components/TeamMemberTasks/TeamMemberTasks.jsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/TeamMemberTasks/TeamMemberTasks.jsx b/src/components/TeamMemberTasks/TeamMemberTasks.jsx index e9cf2c7c6c..ed09169cd6 100644 --- a/src/components/TeamMemberTasks/TeamMemberTasks.jsx +++ b/src/components/TeamMemberTasks/TeamMemberTasks.jsx @@ -438,7 +438,9 @@ const TeamMemberTasks = React.memo(props => { ['Administrator', 'Owner', 'Manager', 'Mentor'].some( role => role === displayUser.role) && - Select Team + + Select Team + { /> + Select Team Code + { /> + Select Color +