From 6eda3c68a8eabadec25a63733902faa5930040fb Mon Sep 17 00:00:00 2001 From: Mo Tarbin Date: Sun, 17 Aug 2025 22:27:58 -0400 Subject: [PATCH] Refactor chore management features to support approval and rejection workflows - Updated RepeatSection to use occurrences instead of dayOccurrences for scheduling. - Enhanced ChoreCard and CompactChoreCard to include approve/reject functionality for pending chores. - Implemented user role checks for approval/rejection capabilities. - Improved UI elements to reflect pending approval states with appropriate icons. - Modified ChoreHistory and ThingsHistory components for better data representation and layout. - Cleaned up unused imports and commented-out code for better readability. --- src/views/ChoreEdit/ChoreView.jsx | 199 +++++++++++---- src/views/ChoreEdit/RepeatSection.jsx | 26 +- src/views/Chores/ChoreCard.jsx | 341 +++++++++++++++++++------- src/views/Chores/CompactChoreCard.jsx | 306 +++++++++++++++++------ src/views/Chores/SortAndGrouping.jsx | 31 ++- src/views/History/ChoreHistory.jsx | 127 ++++++---- src/views/History/HistoryCard.jsx | 12 +- src/views/Things/ThingsHistory.jsx | 128 +++++----- src/views/Things/ThingsView.jsx | 4 - src/views/User/UserActivities.jsx | 52 +++- src/views/User/UserPoints.jsx | 9 +- 11 files changed, 882 insertions(+), 353 deletions(-) diff --git a/src/views/ChoreEdit/ChoreView.jsx b/src/views/ChoreEdit/ChoreView.jsx index abe83a2..07f5bd8 100644 --- a/src/views/ChoreEdit/ChoreView.jsx +++ b/src/views/ChoreEdit/ChoreView.jsx @@ -6,12 +6,15 @@ import { CloseFullscreen, Edit, History, + HourglassEmpty, LowPriority, OpenInFull, PeopleAlt, Person, PlayArrow, SwitchAccessShortcut, + ThumbDown, + ThumbUp, } from '@mui/icons-material' import { Box, @@ -41,15 +44,17 @@ import { useNavigate, useParams, useSearchParams } from 'react-router-dom' import { useImpersonateUser } from '../../contexts/ImpersonateUserContext.jsx' import { useChoreDetails } from '../../queries/ChoreQueries.jsx' -import { useCircleMembers } from '../../queries/UserQueries.jsx' -import { notInCompletionWindow } from '../../utils/Chores.jsx' +import { useCircleMembers, useUserProfile } from '../../queries/UserQueries.jsx' +import { ChoreStatus, notInCompletionWindow } from '../../utils/Chores.jsx' import { getTextColorFromBackgroundColor } from '../../utils/Colors.jsx' import { + ApproveChore, DeleteTimeSession, GetChoreDetailById, GetChoreTimer, MarkChoreComplete, PauseChore, + RejectChore, ResetChoreTimer, SkipChore, StartChore, @@ -84,6 +89,7 @@ const ChoreView = () => { const [timerActionConfig, setTimerActionConfig] = useState({}) const { data: circleMembersData, isLoading: isCircleMembersLoading } = useCircleMembers() + const { data: userProfile } = useUserProfile() const { impersonatedUser } = useImpersonateUser() const { data: choreData, isLoading: isChoreLoading } = @@ -320,6 +326,48 @@ const ChoreView = () => { }) } + const handleApproveChore = () => { + ApproveChore(choreId).then(response => { + if (response.ok) { + response.json().then(data => { + setChore(data.res) + // Invalidate chores cache to refetch data + queryClient.invalidateQueries(['chores']) + }) + } + }) + } + + const handleRejectChore = () => { + RejectChore(choreId).then(response => { + if (response.ok) { + response.json().then(data => { + setChore(data.res) + // Invalidate chores cache to refetch data + queryClient.invalidateQueries(['chores']) + }) + } + }) + } + + // Check if the current user can approve/reject (admin, manager, or task owner) + const canApproveReject = () => { + if (!circleMembersData?.res || !chore) return false + + const currentUser = circleMembersData.res.find( + member => member.userId === (impersonatedUser?.userId || userProfile?.id), + ) + + // User can approve/reject if they are: + // 1. Admin or manager of the circle + // 2. Owner/creator of the task + return ( + currentUser?.role === 'admin' || + currentUser?.role === 'manager' || + chore.createdBy === (impersonatedUser?.userId || userProfile?.id) + ) + } + if (isChoreLoading || isCircleMembersLoading) { // while loading the chore or circle members, return a loading state return @@ -396,7 +444,7 @@ const ChoreView = () => { mb: 1, }} > - {chore.status !== 0 && ( + {[ChoreStatus.ACTIVE, ChoreStatus.PAUSED].includes(chore.status) && ( { variant='soft' > - Completion options + Task Actions @@ -770,59 +818,104 @@ const ChoreView = () => { mb: 1, }} > - + {chore.status === 3 ? ( + // Pending approval: Show approve/reject for admins/managers/owners, grayed out button for others + canApproveReject() ? ( + <> + + + + ) : ( + + ) + ) : ( + // Normal completion flow + <> + - + confirmText: 'Skip', + cancelText: 'Cancel', + onClose: confirmed => { + if (confirmed) { + handleSkippingTask() + } + setConfirmModelConfig({}) + }, + }) + }} + disabled={ + chore.lastCompletedDate !== null && + chore.frequencyType === 'once' + } + startDecorator={} + sx={{ + flex: 1, + }} + > + Skip + + + )} {/* Timer Button - Show split button when timer is active, regular button otherwise */} - {chore.status !== 0 ? ( + {[ChoreStatus.ACTIVE, ChoreStatus.PAUSED].includes(chore.status) ? ( { onClearAllTime={handleClearAllTime} fullWidth /> + ) : chore.status === ChoreStatus.PENDING_APPROVAL ? ( + <> ) : (