import { Check, HourglassEmpty, Pause, PlayArrow, Repeat, ThumbUp, TimesOneMobiledata, Webhook, } from '@mui/icons-material' import { Box, Checkbox, Chip, IconButton, Typography } from '@mui/joy' import { useNavigate } from 'react-router-dom' import { useImpersonateUser } from '../../contexts/ImpersonateUserContext.jsx' import { useLocalization } from '../../contexts/LocalizationContext' import { useCircleMembers, useUserProfile } from '../../queries/UserQueries.jsx' import { getDueDateChipColor, getDueDateChipText, getRecurrentChipText, } from '../../utils/ChoreCardHelpers.jsx' import { notInCompletionWindow } from '../../utils/Chores.jsx' import { getPriorityColor, getTextColorFromBackgroundColor, } from '../../utils/Colors.jsx' import ChoreActionMenu from '../components/ChoreActionMenu' const CompactChoreCard = ({ chore, performers, sx, viewOnly, showActions = true, onChipClick, onAction, // Multi-select props isMultiSelectMode = false, isSelected = false, onSelectionToggle, onlyClickable = false, }) => { const navigate = useNavigate() const { data: userProfile } = useUserProfile() const { timeFormat } = useLocalization() const { data: circleMembersData } = useCircleMembers() const { impersonatedUser } = useImpersonateUser() // 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 getFrequencyIcon = chore => { if (['once', 'no_repeat'].includes(chore.frequencyType)) { return } else if (chore.frequencyType === 'trigger') { return } else { return } } const formatMetadata = () => { const parts = [] // Frequency parts.push(getRecurrentChipText(chore)) // Assignee if (chore.assignedTo) { const assignee = performers.find( p => p.userId === chore.assignedTo, )?.displayName if (assignee) parts.push(assignee) } if (chore.assignedTo === null) { parts.push('Anyone') } // Points if (chore.points > 0) { parts.push(`${chore.points}pts`) } return parts.join(' • ') } return ( {/* Priority bar clickable area */} {chore.priority > 0 && ( { e.stopPropagation() onChipClick({ priority: chore.priority }) }} /> )} {/* Animated transition container for Complete Button / Multi-select checkbox */} {/* Complete Button */} {showActions && ( {chore.status === 3 ? ( // Pending approval: Show approve/reject for admins/managers/owners, grayed out for others canApproveReject() ? ( { e.stopPropagation() onAction('approve', chore) }} sx={{ width: 24, height: 24, borderRadius: '50%', transition: 'all 0.2s ease', '&:hover': { transform: 'scale(1.05)', }, '&:active': { transform: 'scale(0.95)', }, }} > {/* { e.stopPropagation() onAction('reject', chore) }} 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) { onAction('complete', chore) } else if (chore.status === 1) { onAction('pause', chore) } else { onAction('start', chore) } }} disabled={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', }, }} > {chore.status === 0 ? ( ) : chore.status === 1 ? ( ) : ( )} )} )} {/* Multi-select Checkbox */} e.stopPropagation()} /> {/* Content - Center */} {/* Line 1: Name + Due Date */} {/* Chore Name */} {chore.name} {/* Due Date - Inline with name */} {getDueDateChipText(chore.nextDueDate, chore, timeFormat)} {/* Line 2: Metadata */} {getFrequencyIcon(chore)} {formatMetadata()} {/* Labels - Priority chip removed, now shown as vertical bar */} {chore.labelsV2?.map(l => (
{ e.stopPropagation() onChipClick({ label: l }) }} onKeyDown={e => { if (e.key === 'Enter' || e.key === ' ') { e.stopPropagation() onChipClick({ label: l }) } }} style={{ cursor: 'pointer', padding: 0, margin: 0, display: 'flex', alignItems: 'center', }} key={`compact-chorecard-${chore.id}-label-${l.id}`} > {l?.name}
))}
{/* Right side - Action Menu with animation */} {showActions && ( onAction('completeWithNote', chore)} onCompleteWithPastDate={() => onAction('completeWithPastDate', chore) } onChangeAssignee={() => onAction('changeAssignee', chore)} onChangeDueDate={() => onAction('changeDueDate', chore)} onWriteNFC={() => onAction('writeNFC', chore)} onNudge={() => onAction('nudge', chore)} onDelete={() => onAction('delete', chore)} sx={{ width: 32, height: 32, color: 'text.tertiary', flexShrink: 0, '&:hover': { color: 'text.secondary', bgcolor: 'background.level1', }, }} /> )}
) } export default CompactChoreCard