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, }} > - } - sx={{ - flex: 4, - }} - > - Mark as done - + {chore.status === 3 ? ( + // Pending approval: Show approve/reject for admins/managers/owners, grayed out button for others + canApproveReject() ? ( + <> + } + sx={{ + flex: 1, + }} + > + Approve + + } + sx={{ + flex: 1, + }} + > + Reject + + > + ) : ( + } + > + Pending Approval + + ) + ) : ( + // Normal completion flow + <> + } + sx={{ + flex: 4, + }} + > + Mark as done + - { - setConfirmModelConfig({ - isOpen: true, - title: 'Skip Task', + { + setConfirmModelConfig({ + isOpen: true, + title: 'Skip Task', - message: 'Are you sure you want to skip this task?', + message: 'Are you sure you want to skip this task?', - confirmText: 'Skip', - cancelText: 'Cancel', - onClose: confirmed => { - if (confirmed) { - handleSkippingTask() - } - setConfirmModelConfig({}) - }, - }) - }} - disabled={ - chore.lastCompletedDate !== null && - chore.frequencyType === 'once' - } - startDecorator={} - sx={{ - flex: 1, - }} - > - Skip - + 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 ? ( + <>> ) : ( { if ( metadata.weekPattern === 'nth_day_of_month' && - metadata.dayOccurrences?.length + metadata.occurrences?.length ) { - const occurrenceStr = metadata.dayOccurrences + const occurrenceStr = metadata.occurrences .map(w => { if (w === -1) return 'last' return `${w}${w === 1 ? 'st' : w === 2 ? 'nd' : w === 3 ? 'rd' : 'th'}` @@ -127,7 +127,7 @@ const RepeatOnSections = ({ onFrequencyMetadataUpdate({ ...frequencyMetadata, weekPattern: 'every_week', - dayOccurrences: [], + occurrences: [], }) } }, [frequencyMetadata, onFrequencyMetadataUpdate]) @@ -255,7 +255,7 @@ const RepeatOnSections = ({ ...frequencyMetadata, days: [], weekPattern: 'every_week', - dayOccurrences: [], + occurrences: [], }) } else { onFrequencyMetadataUpdate({ @@ -283,10 +283,10 @@ const RepeatOnSections = ({ onFrequencyMetadataUpdate({ ...frequencyMetadata, weekPattern: newPattern, - dayOccurrences: + occurrences: newPattern === 'every_week' ? [] - : frequencyMetadata?.dayOccurrences || [], + : frequencyMetadata?.occurrences || [], }) }} sx={{ gap: 1, '& > div': { p: 1 } }} @@ -330,13 +330,13 @@ const RepeatOnSections = ({ { const currentOccurrences = - frequencyMetadata?.dayOccurrences || [] + frequencyMetadata?.occurrences || [] const newOccurrences = currentOccurrences.includes(option.value) ? currentOccurrences.filter( @@ -345,7 +345,7 @@ const RepeatOnSections = ({ : [...currentOccurrences, option.value] onFrequencyMetadataUpdate({ ...frequencyMetadata, - dayOccurrences: newOccurrences.sort((a, b) => { + occurrences: newOccurrences.sort((a, b) => { if (a === -1) return 1 // Last occurrence goes to end if (b === -1) return -1 return a - b @@ -366,17 +366,17 @@ const RepeatOnSections = ({ color='neutral' onClick={() => { if ( - frequencyMetadata?.dayOccurrences?.length === + frequencyMetadata?.occurrences?.length === DAY_OCCURRENCE_OPTIONS.length ) { onFrequencyMetadataUpdate({ ...frequencyMetadata, - dayOccurrences: [], + occurrences: [], }) } else { onFrequencyMetadataUpdate({ ...frequencyMetadata, - dayOccurrences: DAY_OCCURRENCE_OPTIONS.map( + occurrences: DAY_OCCURRENCE_OPTIONS.map( option => option.value, ), }) @@ -385,7 +385,7 @@ const RepeatOnSections = ({ overlay disableIcon > - {frequencyMetadata?.dayOccurrences?.length === + {frequencyMetadata?.occurrences?.length === DAY_OCCURRENCE_OPTIONS.length ? 'Unselect All' : 'Select All'} diff --git a/src/views/Chores/ChoreCard.jsx b/src/views/Chores/ChoreCard.jsx index 41e98bc..f2fee7a 100644 --- a/src/views/Chores/ChoreCard.jsx +++ b/src/views/Chores/ChoreCard.jsx @@ -3,10 +3,13 @@ import { Check, Delete, Edit, + HourglassEmpty, Pause, PlayArrow, Repeat, Schedule, + ThumbDown, + ThumbUp, TimesOneMobiledata, Toll, Webhook, @@ -28,14 +31,16 @@ import moment from 'moment' import React from 'react' import { useNavigate } from 'react-router-dom' import { useImpersonateUser } from '../../contexts/ImpersonateUserContext.jsx' -import { useUserProfile } from '../../queries/UserQueries.jsx' +import { useCircleMembers, useUserProfile } from '../../queries/UserQueries.jsx' import { useNotification } from '../../service/NotificationProvider' import { notInCompletionWindow } from '../../utils/Chores.jsx' import { getTextColorFromBackgroundColor } from '../../utils/Colors.jsx' import { + ApproveChore, DeleteChore, MarkChoreComplete, PauseChore, + RejectChore, StartChore, UpdateChoreAssignee, UpdateDueDate, @@ -76,6 +81,7 @@ const ChoreCard = ({ const [secondsLeftToCancel, setSecondsLeftToCancel] = React.useState(null) const [timeoutId, setTimeoutId] = React.useState(null) const { data: userProfile } = useUserProfile() + const { data: circleMembersData } = useCircleMembers() const { impersonatedUser } = useImpersonateUser() @@ -234,6 +240,46 @@ const ChoreCard = ({ }) } + const handleApproveChore = () => { + resetSwipe() + ApproveChore(chore.id).then(response => { + if (response.ok) { + response.json().then(data => { + onChoreUpdate(data.res, 'approved') + }) + } + }) + } + + const handleRejectChore = () => { + resetSwipe() + RejectChore(chore.id).then(response => { + if (response.ok) { + response.json().then(data => { + onChoreUpdate(data.res, 'rejected') + }) + } + }) + } + + // 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) + ) + } + // Swipe gesture handlers const handleTouchStart = e => { if (isMultiSelectMode || viewOnly) return @@ -642,32 +688,80 @@ const ChoreCard = ({ onMouseEnter={handleActionAreaMouseEnter} onMouseLeave={handleActionAreaMouseLeave} > - { - e.stopPropagation() - resetSwipe() - - if (chore.status !== 0) { - handleTaskCompletion() - } else { - handleChoreStart() - } - }} - sx={{ - width: 40, - height: 40, - mx: 1, - }} - > - {chore.status !== 0 ? ( - + {chore.status === 3 ? ( + // Pending approval: Show approve/reject for admins/managers/owners + canApproveReject() ? ( + <> + {/* + + */} + + + + > ) : ( - - )} - + + + + ) + ) : ( + { + e.stopPropagation() + resetSwipe() + + if (chore.status !== 0) { + handleTaskCompletion() + } else { + handleChoreStart() + } + }} + sx={{ + width: 40, + height: 40, + mx: 1, + }} + > + {chore.status !== 0 ? ( + + ) : ( + + )} + + )} {/* */} - { - e.stopPropagation() - switch (chore.status) { - case 0: // Not started - handleTaskCompletion() - break - case 1: // In progress - handleChorePause() - break - case 2: // Paused - handleChoreStart() - break - default: - break - } - }} - disabled={isPendingCompletion || notInCompletionWindow(chore)} - sx={{ - borderRadius: '50%', - minWidth: 50, - height: 50, - zIndex: 1, - transition: 'all 0.2s ease', - '&:hover': { - transform: 'scale(1.05)', - }, - '&:active': { - transform: 'scale(0.95)', - }, - '&:disabled': { - opacity: 0.5, - transform: 'none', - }, - }} - > - - {isPendingCompletion ? ( - - ) : chore.status === 0 ? ( - - ) : chore.status === 1 ? ( - - ) : ( - - )} - {isPendingCompletion && ( - + { + e.stopPropagation() + handleApproveChore() }} - /> - )} - - + sx={{ + borderRadius: '50%', + minWidth: 50, + height: 50, + zIndex: 1, + transition: 'all 0.2s ease', + '&:hover': { + transform: 'scale(1.05)', + }, + '&:active': { + transform: 'scale(0.95)', + }, + '&:disabled': { + opacity: 0.5, + transform: 'none', + }, + }} + > + + + {/* { + e.stopPropagation() + handleRejectChore() + }} + sx={{ + borderRadius: '50%', + minWidth: 40, + height: 40, + zIndex: 1, + transition: 'all 0.2s ease', + '&:hover': { + transform: 'scale(1.05)', + }, + '&:active': { + transform: 'scale(0.95)', + }, + }} + > + + */} + + ) : ( + + + + ) + ) : ( + { + e.stopPropagation() + switch (chore.status) { + case 0: // Not started + handleTaskCompletion() + break + case 1: // In progress + handleChorePause() + break + case 2: // Paused + handleChoreStart() + break + default: + break + } + }} + disabled={ + isPendingCompletion || notInCompletionWindow(chore) + } + sx={{ + borderRadius: '50%', + minWidth: 50, + height: 50, + zIndex: 1, + transition: 'all 0.2s ease', + '&:hover': { + transform: 'scale(1.05)', + }, + '&:active': { + transform: 'scale(0.95)', + }, + '&:disabled': { + opacity: 0.5, + transform: 'none', + }, + }} + > + + {isPendingCompletion ? ( + + ) : chore.status === 0 ? ( + + ) : chore.status === 1 ? ( + + ) : ( + + )} + {isPendingCompletion && ( + + )} + + + )} { + resetSwipe() + ApproveChore(chore.id).then(response => { + if (response.ok) { + response.json().then(data => { + onChoreUpdate(data.res, 'approved') + }) + } + }) + } + + const handleRejectChore = () => { + resetSwipe() + RejectChore(chore.id).then(response => { + if (response.ok) { + response.json().then(data => { + onChoreUpdate(data.res, 'rejected') + }) + } + }) + } + + // 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) + ) + } + // Utility functions const getDueDateText = nextDueDate => { if (chore.nextDueDate === null) return 'No Due Date' @@ -641,38 +687,81 @@ const CompactChoreCard = ({ onMouseEnter={handleActionAreaMouseEnter} onMouseLeave={handleActionAreaMouseLeave} > - { - e.stopPropagation() - resetSwipe() - - if (chore.status === 0 || chore.status === 2) { - handleChoreStart() - } else { - // handleChorePause() - handleTaskCompletion() - } - }} - sx={{ - width: 40, - height: 40, - mx: 1, - // bgcolor: 'success.100', - // color: 'success.600', - // '&:hover': { - // bgcolor: 'success.200', - // }, - }} - > - {chore.status !== 1 ? ( - + {chore.status === 3 ? ( + // Pending approval: Show approve/reject for admins/managers/owners + canApproveReject() ? ( + <> + {/* + + */} + + + + > ) : ( - - )} - + + + + ) + ) : ( + { + e.stopPropagation() + resetSwipe() + + if (chore.status === 0 || chore.status === 2) { + handleChoreStart() + } else { + // handleChorePause() + handleTaskCompletion() + } + }} + sx={{ + width: 40, + height: 40, + mx: 1, + }} + > + {chore.status !== 1 ? ( + + ) : ( + + )} + + )} - { - e.stopPropagation() - if (chore.status === 0) { - handleTaskCompletion() - } else if (chore.status === 1) { - handleChorePause() - } else { - handleChoreStart() - } - }} - disabled={isPendingCompletion || notInCompletionWindow(chore)} - sx={{ - width: 32, - height: 32, - borderRadius: '50%', - transition: 'all 0.2s ease', - '&:hover': { - transform: 'scale(1.05)', - }, - - '&:active': { - transform: 'scale(0.95)', - }, - '&:disabled': { - opacity: 0.5, - transform: 'none', - }, - }} - > - {isPendingCompletion ? ( - - ) : chore.status === 0 ? ( - - ) : chore.status === 1 ? ( - + {chore.status === 3 ? ( + // Pending approval: Show approve/reject for admins/managers/owners, grayed out for others + canApproveReject() ? ( + + { + e.stopPropagation() + handleApproveChore() + }} + sx={{ + width: 24, + height: 24, + borderRadius: '50%', + transition: 'all 0.2s ease', + '&:hover': { + transform: 'scale(1.05)', + }, + '&:active': { + transform: 'scale(0.95)', + }, + }} + > + + + {/* { + e.stopPropagation() + handleRejectChore() + }} + sx={{ + width: 24, + height: 24, + borderRadius: '50%', + transition: 'all 0.2s ease', + '&:hover': { + transform: 'scale(1.05)', + }, + '&:active': { + transform: 'scale(0.95)', + }, + }} + > + + */} + ) : ( - - )} - + + + + ) + ) : ( + { + e.stopPropagation() + if (chore.status === 0) { + handleTaskCompletion() + } else if (chore.status === 1) { + handleChorePause() + } else { + handleChoreStart() + } + }} + disabled={isPendingCompletion || notInCompletionWindow(chore)} + sx={{ + width: 32, + height: 32, + borderRadius: '50%', + transition: 'all 0.2s ease', + '&:hover': { + transform: 'scale(1.05)', + }, + + '&:active': { + transform: 'scale(0.95)', + }, + '&:disabled': { + opacity: 0.5, + transform: 'none', + }, + }} + > + {isPendingCompletion ? ( + + ) : chore.status === 0 ? ( + + ) : chore.status === 1 ? ( + + ) : ( + + )} + + )} {/* Multi-select Checkbox */} diff --git a/src/views/Chores/SortAndGrouping.jsx b/src/views/Chores/SortAndGrouping.jsx index 3f128ce..e5d0ded 100644 --- a/src/views/Chores/SortAndGrouping.jsx +++ b/src/views/Chores/SortAndGrouping.jsx @@ -145,7 +145,7 @@ const SortAndGrouping = ({ - Assigned to: + Assigned to : @@ -174,6 +174,20 @@ const SortAndGrouping = ({ Assigned to me + {/* { + setFilter('assignable_to_me') + handleMenuClose() + }} + > + + Available for me + */} + { @@ -187,6 +201,21 @@ const SortAndGrouping = ({ /> Assigned to others + {/* +// i need this but i think it have a bad UX and confusing so commenting it for now + { + setFilter('created_by_me') + handleMenuClose() + }} + > + + Created by me + */} > ) diff --git a/src/views/History/ChoreHistory.jsx b/src/views/History/ChoreHistory.jsx index 2bc3dbf..3bedbde 100644 --- a/src/views/History/ChoreHistory.jsx +++ b/src/views/History/ChoreHistory.jsx @@ -3,6 +3,7 @@ import { Checklist, EventBusy, Group, + History, Star, Timelapse, TrendingUp, @@ -11,7 +12,6 @@ import { Box, Button, Card, - CardContent, Container, Grid, List, @@ -22,6 +22,7 @@ import moment from 'moment' import { useEffect, useState } from 'react' import { Link, useParams } from 'react-router-dom' import { LoadingScreen } from '../../components/animations' +import { ChoreHistoryStatus } from '../../utils/Chores' import { DeleteChoreHistory, GetAllCircleMembers, @@ -98,15 +99,12 @@ const ChoreHistory = () => { const userCompletedByMost = Object.keys(userHistories).reduce((a, b) => userHistories[a] > userHistories[b] ? a : b, ) - const userCompletedByLeast = Object.keys(userHistories).reduce((a, b) => - userHistories[a] < userHistories[b] ? a : b, - ) const historyInfo = [ { icon: , - text: 'Total Completed', - subtext: `${histories.length} times`, + text: 'All Completed', + subtext: `${histories.filter(h => h.status === ChoreHistoryStatus.COMPLETED).length} times`, }, { icon: , @@ -117,14 +115,14 @@ const ChoreHistory = () => { }, { icon: , - text: 'Maximum Delay', + text: 'Longest Delay', subtext: moment.duration(maxDelayMoment).isValid() ? moment.duration(maxDelayMoment).humanize() : 'Never late', }, { icon: , - text: 'Top Performer', + text: 'Completed Most', subtext: `${ performers.find(p => p.userId === Number(userCompletedByMost)) ?.displayName || 'Unknown' @@ -132,12 +130,12 @@ const ChoreHistory = () => { }, { icon: , - text: 'Team Members', - subtext: `${Object.keys(userHistories).length} active`, + text: 'Members Involved', + subtext: `${Object.keys(userHistories).length} members`, }, { icon: , - text: 'Last Completed By', + text: 'Last Completed', subtext: `${ performers.find(p => p.userId === Number(histories[0].completedBy)) ?.displayName || 'Unknown' @@ -191,52 +189,76 @@ const ChoreHistory = () => { {/* Enhanced Header Section */} - {/* Statistics Cards Grid */} - + {/* Statistics Cards Grid - Compact Design */} + + + + Task Summary + + + {historyInfo.map((info, index) => ( - + - - {info.icon} + + - {info.icon} - - {info.text} - - - - - {info.subtext || '--'} - - - + {info.text} + + + {info.subtext || '--'} + + ))} @@ -245,9 +267,12 @@ const ChoreHistory = () => { {/* History Section Header */} - - - Completion History + + + Task Activity diff --git a/src/views/History/HistoryCard.jsx b/src/views/History/HistoryCard.jsx index cd2e1fe..bcede5a 100644 --- a/src/views/History/HistoryCard.jsx +++ b/src/views/History/HistoryCard.jsx @@ -4,8 +4,10 @@ import { Check, CheckCircle, EventNote, + HourglassEmpty, Person, Redo, + ThumbDown, Timelapse, Toll, } from '@mui/icons-material' @@ -121,6 +123,8 @@ const HistoryCard = ({ 0: { icon: , color: 'primary' }, // Started 1: { icon: , color: 'success' }, // Completed 2: { icon: , color: 'warning' }, // Skipped + 3: { icon: , color: 'neutral' }, // Pending Approval + 4: { icon: , color: 'danger' }, // Rejected } const config = statusMap[historyEntry.status] || statusMap[1] @@ -182,7 +186,13 @@ const HistoryCard = ({ ? 'In Progress' : historyEntry.status === 1 ? 'Completed' - : 'Skipped'} + : historyEntry.status === 2 + ? 'Skipped' + : historyEntry.status === 3 + ? 'Pending Approval' + : historyEntry.status === 4 + ? 'Rejected' + : 'Completed'} }> diff --git a/src/views/Things/ThingsHistory.jsx b/src/views/Things/ThingsHistory.jsx index dfdf562..daba9bd 100644 --- a/src/views/Things/ThingsHistory.jsx +++ b/src/views/Things/ThingsHistory.jsx @@ -14,7 +14,6 @@ import { Box, Button, Card, - CardContent, Chip, Container, Grid, @@ -22,7 +21,6 @@ import { ListDivider, ListItem, ListItemContent, - Stack, Typography, } from '@mui/joy' import { useTheme } from '@mui/joy/styles' @@ -188,68 +186,78 @@ const ThingsHistory = () => { return ( {/* Enhanced Analytics Header Section */} - - - - - - Things Details - - - Quick overview of the thing's history and analytics - - + + + + + Things Overview + - {/* Statistics Cards Grid */} - + {/* Statistics Cards Grid - Compact Design */} + {analyticsData.map((info, index) => ( - + - - {info.icon} + + - {info.icon} - - {info.text} - - - - - {info.subtext || '--'} - - - + {info.text} + + + {info.subtext || '--'} + + ))} @@ -260,9 +268,9 @@ const ThingsHistory = () => { {thingsHistory.every(history => !isNaN(history.state)) && thingsHistory.length > 1 && ( - + Data Visualization @@ -324,9 +332,13 @@ const ThingsHistory = () => { )} {/* History Section Header */} - - - + + + + Change History diff --git a/src/views/Things/ThingsView.jsx b/src/views/Things/ThingsView.jsx index 7298a98..eaab6b4 100644 --- a/src/views/Things/ThingsView.jsx +++ b/src/views/Things/ThingsView.jsx @@ -662,10 +662,6 @@ const ThingsView = () => { diff --git a/src/views/User/UserActivities.jsx b/src/views/User/UserActivities.jsx index 90788cf..8d69aad 100644 --- a/src/views/User/UserActivities.jsx +++ b/src/views/User/UserActivities.jsx @@ -1,9 +1,17 @@ -import CancelIcon from '@mui/icons-material/Cancel' import CheckCircleIcon from '@mui/icons-material/CheckCircle' -import CircleIcon from '@mui/icons-material/Circle' +import HourglassEmptyIcon from '@mui/icons-material/HourglassEmpty' +import ThumbDownIcon from '@mui/icons-material/ThumbDown' +import TimelapseIcon from '@mui/icons-material/Timelapse' import { Cell, Pie, PieChart, Tooltip } from 'recharts' -import { EventBusy, Group, Timeline, Toll } from '@mui/icons-material' +import { + Block, + Check, + EventBusy, + Group, + Timeline, + Toll, +} from '@mui/icons-material' import { Avatar, Box, @@ -44,11 +52,22 @@ const groupByDate = history => { return aggregated } -const ChoreHistoryItem = ({ time, name, points, status }) => { - const statusIcon = { - completed: , - missed: , - pending: , +const ChoreHistoryItem = ({ time, name, points, status, performer }) => { + const getStatusIcon = status => { + switch (status) { + case 0: + return + case 1: + return + case 2: + return + case 3: + return + case 4: + return + default: + return + } } return ( @@ -56,15 +75,25 @@ const ChoreHistoryItem = ({ time, name, points, status }) => { {time} - - {statusIcon[status] ? statusIcon[status] : statusIcon['completed']} + + {getStatusIcon(status)} @@ -795,7 +824,6 @@ const UserActivites = () => { sx={{ display: 'flex', flexDirection: 'column', - px: { xs: 2, sm: 3 }, }} > {/* Main Content Area - Mobile: Stack vertically, Desktop: Side by side */} diff --git a/src/views/User/UserPoints.jsx b/src/views/User/UserPoints.jsx index ba092ff..ad21edd 100644 --- a/src/views/User/UserPoints.jsx +++ b/src/views/User/UserPoints.jsx @@ -10,6 +10,7 @@ import { import { AccountBalanceWallet, Analytics, + AssignmentTurnedIn, CreditCard, EmojiEvents, MilitaryTech, @@ -530,7 +531,13 @@ const UserPoints = () => { - + {leaderboardMode === 'points' ? ( + + ) : ( + + )}