Merge branch 'dev'

This commit is contained in:
Mo Tarbin
2025-06-01 00:47:57 -04:00
6 changed files with 351 additions and 457 deletions

View File

@@ -30,7 +30,6 @@ import {
MenuItem,
Sheet,
Snackbar,
styled,
Typography,
} from '@mui/joy'
import { Divider } from '@mui/material'
@@ -54,16 +53,6 @@ import ConfirmationModal from '../Modals/Inputs/ConfirmationModal'
import LoadingComponent from '../components/Loading.jsx'
import RichTextEditor from '../components/RichTextEditor.jsx'
import SubTasks from '../components/SubTask.jsx'
const IconCard = styled('div')({
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#f0f0f0', // Adjust the background color as needed
borderRadius: '50%',
minWidth: '40px',
height: '40px',
marginRight: '16px',
})
const ChoreView = () => {
const [chore, setChore] = useState({})

View File

@@ -1,29 +1,9 @@
import {
Archive,
CancelScheduleSend,
Check,
CopyAll,
Delete,
Edit,
HorizontalRule,
KeyboardControlKey,
KeyboardDoubleArrowUp,
LocalOffer,
ManageSearch,
MoreTime,
MoreVert,
Nfc,
NoteAdd,
PriorityHigh,
RecordVoiceOver,
Repeat,
Report,
SwitchAccessShortcut,
TimesOneMobiledata,
Toll,
Unarchive,
Update,
ViewCarousel,
Webhook,
} from '@mui/icons-material'
import {
@@ -33,16 +13,13 @@ import {
Card,
Chip,
CircularProgress,
Divider,
Grid,
IconButton,
Menu,
MenuItem,
Snackbar,
Typography,
} from '@mui/joy'
import moment from 'moment'
import React, { useEffect } from 'react'
import React from 'react'
import { useNavigate } from 'react-router-dom'
import { useImpersonateUser } from '../../contexts/ImpersonateUserContext.jsx'
import { UserContext } from '../../contexts/UserContext'
@@ -50,11 +27,8 @@ import { useError } from '../../service/ErrorProvider'
import { notInCompletionWindow } from '../../utils/Chores.jsx'
import { getTextColorFromBackgroundColor } from '../../utils/Colors.jsx'
import {
ArchiveChore,
DeleteChore,
MarkChoreComplete,
SkipChore,
UnArchiveChore,
UpdateChoreAssignee,
UpdateDueDate,
} from '../../utils/Fetcher'
@@ -64,17 +38,16 @@ import DateModal from '../Modals/Inputs/DateModal'
import SelectModal from '../Modals/Inputs/SelectModal'
import TextModal from '../Modals/Inputs/TextModal'
import WriteNFCModal from '../Modals/Inputs/WriteNFCModal'
import ChoreActionMenu from '../components/ChoreActionMenu'
const ChoreCard = ({
chore,
performers,
onChoreUpdate,
onChoreRemove,
userLabels,
sx,
viewOnly,
onChipClick,
}) => {
const [activeUserId, setActiveUserId] = React.useState(0)
const [isChangeDueDateModalOpen, setIsChangeDueDateModalOpen] =
React.useState(false)
const [isCompleteWithPastDateModalOpen, setIsCompleteWithPastDateModalOpen] =
@@ -85,10 +58,7 @@ const ChoreCard = ({
React.useState(false)
const [confirmModelConfig, setConfirmModelConfig] = React.useState({})
const [isNFCModalOpen, setIsNFCModalOpen] = React.useState(false)
const [anchorEl, setAnchorEl] = React.useState(null)
const menuRef = React.useRef(null)
const navigate = useNavigate()
const [isDisabled, setIsDisabled] = React.useState(false)
const [isPendingCompletion, setIsPendingCompletion] = React.useState(false)
const [secondsLeftToCancel, setSecondsLeftToCancel] = React.useState(null)
@@ -97,39 +67,7 @@ const ChoreCard = ({
const { impersonatedUser } = useImpersonateUser()
const { showError } = useError()
useEffect(() => {
document.addEventListener('mousedown', handleMenuOutsideClick)
return () => {
document.removeEventListener('mousedown', handleMenuOutsideClick)
}
}, [anchorEl])
const handleMenuOpen = event => {
setAnchorEl(event.currentTarget)
}
const handleMenuClose = () => {
setAnchorEl(null)
}
const handleMenuOutsideClick = event => {
if (
anchorEl &&
!anchorEl.contains(event.target) &&
!menuRef.current.contains(event.target)
) {
handleMenuClose()
}
}
const handleEdit = () => {
navigate(`/chores/${chore.id}/edit`)
}
const handleClone = () => {
navigate(`/chores/${chore.id}/edit?clone=true`)
}
const handleView = () => {
navigate(`/chores/${chore.id}`)
}
const handleDelete = () => {
setConfirmModelConfig({
isOpen: true,
@@ -149,30 +87,6 @@ const ChoreCard = ({
},
})
}
const handleArchive = () => {
if (chore.isActive) {
ArchiveChore(chore.id).then(response => {
if (response.ok) {
response.json().then(data => {
const newChore = { ...chore, isActive: false }
onChoreUpdate(newChore, 'archive')
})
}
})
} else {
UnArchiveChore(chore.id).then(response => {
if (response.ok) {
response.json().then(data => {
const newChore = { ...chore, isActive: true }
onChoreUpdate(newChore, 'unarchive')
})
}
})
}
handleMenuClose()
}
const handleTaskCompletion = () => {
setIsPendingCompletion(true)
@@ -235,10 +149,6 @@ const ChoreCard = ({
}
const handleChangeDueDate = newDate => {
if (activeUserId === null) {
alert('Please select a performer')
return
}
UpdateDueDate(chore.id, newDate).then(response => {
if (response.ok) {
response.json().then(data => {
@@ -250,11 +160,6 @@ const ChoreCard = ({
}
const handleCompleteWithPastDate = newDate => {
if (activeUserId === null) {
alert('Please select a performer')
return
}
MarkChoreComplete(
chore.id,
impersonatedUser ? { completedBy: impersonatedUser.userId } : null,
@@ -318,29 +223,6 @@ const ChoreCard = ({
return 'neutral'
}
const getIconForLabel = label => {
if (!label || label.trim() === '') return <></>
switch (String(label).toLowerCase()) {
case 'high':
return <KeyboardDoubleArrowUp />
case 'important':
return <Report />
default:
return <LocalOffer />
}
}
const getPriorityIcon = priority => {
switch (Number(priority)) {
case 1:
return <PriorityHigh />
case 2:
return <KeyboardDoubleArrowUp />
case 3:
return <KeyboardControlKey />
default:
return <HorizontalRule />
}
}
const getRecurrentChipText = chore => {
// if chore.frequencyMetadata is type string then parse it otherwise assigned to the metadata:
const metadata =
@@ -678,135 +560,19 @@ const ChoreCard = ({
)}
</div>
</IconButton>
<IconButton
// sx={{ width: 15 }}
variant='soft'
color='success'
onClick={handleMenuOpen}
sx={{
borderRadius: '50%',
width: 25,
height: 25,
position: 'relative',
left: -10,
}}
>
<MoreVert />
</IconButton>
{/* </ButtonGroup> */}
<Menu
size='lg'
ref={menuRef}
anchorEl={anchorEl}
open={Boolean(anchorEl)}
onClose={handleMenuClose}
>
<MenuItem
onClick={() => {
setIsCompleteWithNoteModalOpen(true)
}}
>
<NoteAdd />
Complete with note
</MenuItem>
<MenuItem
onClick={() => {
setIsCompleteWithPastDateModalOpen(true)
}}
>
<Update />
Complete in past
</MenuItem>
<MenuItem
onClick={() => {
SkipChore(chore.id)
.then(response => {
if (response.ok) {
response.json().then(data => {
const newChore = data.res
onChoreUpdate(newChore, 'skipped')
handleMenuClose()
})
}
})
.catch(error => {
if (error?.queued) {
showError({
title: 'Failed to update',
message:
'Request will be processed when you are online',
})
} else {
showError({
title: 'Failed to update',
message: error,
})
}
})
}}
>
<SwitchAccessShortcut />
Skip to next due date
</MenuItem>
<MenuItem
onClick={() => {
setIsChangeAssigneeModalOpen(true)
}}
>
<RecordVoiceOver />
Delegate to someone else
</MenuItem>
<Divider />
<MenuItem
onClick={() => {
navigate(`/chores/${chore.id}/history`)
}}
>
<ManageSearch />
History
</MenuItem>
<Divider />
<MenuItem
onClick={() => {
setIsChangeDueDateModalOpen(true)
}}
>
<MoreTime />
Change due date
</MenuItem>
<MenuItem
onClick={() => {
// write current chore URL to NFC
// writeToNFC(`${window.location.origin}/chores/${chore.id}`)
setIsNFCModalOpen(true)
}}
>
<Nfc />
Write to NFC
</MenuItem>
<MenuItem onClick={handleEdit}>
<Edit />
Edit
</MenuItem>
<MenuItem onClick={handleClone}>
<CopyAll />
Clone
</MenuItem>
<MenuItem onClick={handleView}>
<ViewCarousel />
View
</MenuItem>
<MenuItem onClick={handleArchive} color='neutral'>
{chore.isActive ? <Archive /> : <Unarchive />}
{chore.isActive ? 'Archive' : 'Unarchive'}
</MenuItem>
<Divider />
<MenuItem onClick={handleDelete} color='danger'>
<Delete />
Delete
</MenuItem>
</Menu>
<ChoreActionMenu
chore={chore}
onChoreUpdate={onChoreUpdate}
onChoreRemove={onChoreRemove}
onCompleteWithNote={() => setIsCompleteWithNoteModalOpen(true)}
onCompleteWithPastDate={() =>
setIsCompleteWithPastDateModalOpen(true)
}
onChangeAssignee={() => setIsChangeAssigneeModalOpen(true)}
onChangeDueDate={() => setIsChangeDueDateModalOpen(true)}
onWriteNFC={() => setIsNFCModalOpen(true)}
onDelete={handleDelete}
/>
</Box>
</Grid>
</Grid>

View File

@@ -1,22 +1,8 @@
import {
Archive,
CancelScheduleSend,
Check,
CopyAll,
Delete,
Edit,
ManageSearch,
MoreTime,
MoreVert,
Nfc,
NoteAdd,
RecordVoiceOver,
Repeat,
SwitchAccessShortcut,
TimesOneMobiledata,
Unarchive,
Update,
ViewCarousel,
Webhook,
} from '@mui/icons-material'
import {
@@ -24,15 +10,12 @@ import {
Button,
Chip,
CircularProgress,
Divider,
IconButton,
Menu,
MenuItem,
Snackbar,
Typography,
} from '@mui/joy'
import moment from 'moment'
import React, { useEffect } from 'react'
import React from 'react'
import { useNavigate } from 'react-router-dom'
import { useImpersonateUser } from '../../contexts/ImpersonateUserContext.jsx'
import { UserContext } from '../../contexts/UserContext'
@@ -40,11 +23,8 @@ import { useError } from '../../service/ErrorProvider'
import { notInCompletionWindow } from '../../utils/Chores.jsx'
import { getTextColorFromBackgroundColor } from '../../utils/Colors.jsx'
import {
ArchiveChore,
DeleteChore,
MarkChoreComplete,
SkipChore,
UnArchiveChore,
UpdateChoreAssignee,
UpdateDueDate,
} from '../../utils/Fetcher'
@@ -54,6 +34,7 @@ import DateModal from '../Modals/Inputs/DateModal'
import SelectModal from '../Modals/Inputs/SelectModal'
import TextModal from '../Modals/Inputs/TextModal'
import WriteNFCModal from '../Modals/Inputs/WriteNFCModal'
import ChoreActionMenu from '../components/ChoreActionMenu'
const CompactChoreCard = ({
chore,
@@ -64,7 +45,6 @@ const CompactChoreCard = ({
viewOnly,
onChipClick,
}) => {
const [activeUserId, setActiveUserId] = React.useState(0)
const [isChangeDueDateModalOpen, setIsChangeDueDateModalOpen] =
React.useState(false)
const [isCompleteWithPastDateModalOpen, setIsCompleteWithPastDateModalOpen] =
@@ -75,10 +55,7 @@ const CompactChoreCard = ({
React.useState(false)
const [confirmModelConfig, setConfirmModelConfig] = React.useState({})
const [isNFCModalOpen, setIsNFCModalOpen] = React.useState(false)
const [anchorEl, setAnchorEl] = React.useState(null)
const menuRef = React.useRef(null)
const navigate = useNavigate()
const [isDisabled, setIsDisabled] = React.useState(false)
const [isPendingCompletion, setIsPendingCompletion] = React.useState(false)
const [secondsLeftToCancel, setSecondsLeftToCancel] = React.useState(null)
@@ -88,44 +65,7 @@ const CompactChoreCard = ({
const { showError } = useError()
useEffect(() => {
document.addEventListener('mousedown', handleMenuOutsideClick)
return () => {
document.removeEventListener('mousedown', handleMenuOutsideClick)
}
}, [anchorEl])
const handleMenuOpen = event => {
setAnchorEl(event.currentTarget)
}
const handleMenuClose = () => {
setAnchorEl(null)
}
const handleMenuOutsideClick = event => {
if (
anchorEl &&
!anchorEl.contains(event.target) &&
!menuRef.current.contains(event.target)
) {
handleMenuClose()
}
}
// All the existing handler methods (same as original ChoreCard)
const handleEdit = () => {
navigate(`/chores/${chore.id}/edit`)
}
const handleClone = () => {
navigate(`/chores/${chore.id}/edit?clone=true`)
}
const handleView = () => {
navigate(`/chores/${chore.id}`)
}
const handleDelete = () => {
setConfirmModelConfig({
isOpen: true,
@@ -146,29 +86,6 @@ const CompactChoreCard = ({
})
}
const handleArchive = () => {
if (chore.isActive) {
ArchiveChore(chore.id).then(response => {
if (response.ok) {
response.json().then(data => {
const newChore = { ...chore, isActive: false }
onChoreUpdate(newChore, 'archive')
})
}
})
} else {
UnArchiveChore(chore.id).then(response => {
if (response.ok) {
response.json().then(data => {
const newChore = { ...chore, isActive: true }
onChoreUpdate(newChore, 'unarchive')
})
}
})
}
handleMenuClose()
}
const handleTaskCompletion = () => {
setIsPendingCompletion(true)
let seconds = 3
@@ -230,10 +147,6 @@ const CompactChoreCard = ({
}
const handleChangeDueDate = newDate => {
if (activeUserId === null) {
alert('Please select a performer')
return
}
UpdateDueDate(chore.id, newDate).then(response => {
if (response.ok) {
response.json().then(data => {
@@ -245,11 +158,6 @@ const CompactChoreCard = ({
}
const handleCompleteWithPastDate = newDate => {
if (activeUserId === null) {
alert('Please select a performer')
return
}
MarkChoreComplete(
chore.id,
impersonatedUser ? { completedBy: impersonatedUser.userId } : null,
@@ -654,113 +562,30 @@ const CompactChoreCard = ({
)}
</IconButton>
{/* Menu Button */}
<IconButton
{/* Chore Action Menu */}
<ChoreActionMenu
variant='plain'
color='neutral'
size='sm'
onClick={e => {
e.stopPropagation()
handleMenuOpen(e)
}}
chore={chore}
onChoreUpdate={onChoreUpdate}
onChoreRemove={onChoreRemove}
onCompleteWithNote={() => setIsCompleteWithNoteModalOpen(true)}
onCompleteWithPastDate={() =>
setIsCompleteWithPastDateModalOpen(true)
}
onChangeAssignee={() => setIsChangeAssigneeModalOpen(true)}
onChangeDueDate={() => setIsChangeDueDateModalOpen(true)}
onWriteNFC={() => setIsNFCModalOpen(true)}
onDelete={handleDelete}
sx={{
width: 28,
height: 28,
opacity: 0.6,
// opacity: 0.6,
'&:hover': {
opacity: 1,
},
}}
>
<MoreVert sx={{ fontSize: 14 }} />
</IconButton>
/>
</Box>
{/* Menu */}
<Menu
ref={menuRef}
anchorEl={anchorEl}
open={Boolean(anchorEl)}
onClose={handleMenuClose}
>
<MenuItem onClick={() => setIsCompleteWithNoteModalOpen(true)}>
<NoteAdd />
Complete with note
</MenuItem>
<MenuItem onClick={() => setIsCompleteWithPastDateModalOpen(true)}>
<Update />
Complete in past
</MenuItem>
<MenuItem
onClick={() => {
SkipChore(chore.id)
.then(response => {
if (response.ok) {
response.json().then(data => {
const newChore = data.res
onChoreUpdate(newChore, 'skipped')
handleMenuClose()
})
}
})
.catch(error => {
if (error?.queued) {
showError({
title: 'Failed to update',
message: 'Request will be processed when you are online',
})
} else {
showError({
title: 'Failed to update',
message: error,
})
}
})
}}
>
<SwitchAccessShortcut />
Skip to next due date
</MenuItem>
<MenuItem onClick={() => setIsChangeAssigneeModalOpen(true)}>
<RecordVoiceOver />
Delegate to someone else
</MenuItem>
<Divider />
<MenuItem onClick={() => navigate(`/chores/${chore.id}/history`)}>
<ManageSearch />
History
</MenuItem>
<Divider />
<MenuItem onClick={() => setIsChangeDueDateModalOpen(true)}>
<MoreTime />
Change due date
</MenuItem>
<MenuItem onClick={() => setIsNFCModalOpen(true)}>
<Nfc />
Write to NFC
</MenuItem>
<MenuItem onClick={handleEdit}>
<Edit />
Edit
</MenuItem>
<MenuItem onClick={handleClone}>
<CopyAll />
Clone
</MenuItem>
<MenuItem onClick={handleView}>
<ViewCarousel />
View
</MenuItem>
<MenuItem onClick={handleArchive} color='neutral'>
{chore.isActive ? <Archive /> : <Unarchive />}
{chore.isActive ? 'Archive' : 'Unarchive'}
</MenuItem>
<Divider />
<MenuItem onClick={handleDelete} color='danger'>
<Delete />
Delete
</MenuItem>
</Menu>
</Box>
{/* All modals (same as original) */}

View File

@@ -1,4 +1,4 @@
import { CheckCircle, Key, Security, Smartphone } from '@mui/icons-material'
import { CheckCircle, Security, Smartphone } from '@mui/icons-material'
import {
Alert,
Box,
@@ -264,7 +264,7 @@ const MFASettings = () => {
</Box>
</Box>
</Card>
{/*
{mfaEnabled && (
<Card variant='outlined'>
<Box className='flex items-center justify-between'>
@@ -288,7 +288,7 @@ const MFASettings = () => {
</Button>
</Box>
</Card>
)}
)} */}
{/* Setup MFA Modal */}
<Modal open={setupModalOpen} onClose={closeSetupModal}>

View File

@@ -122,7 +122,18 @@ const CalendarView = ({ chores }) => {
}
/>
{!selectedDate && (
<Grid container ml={-3} mt={1}>
<Grid
container
ml={3}
mt={1}
// start from left:
sx={{
width: '100%',
display: 'flex',
// alignItems: 'center',
justifyContent: 'start',
}}
>
{/* Show legend with current user first, then other circle members who have assignments */}
{(() => {
const assignedUserIds = new Set(
@@ -171,7 +182,7 @@ const CalendarView = ({ chores }) => {
backgroundColor: item.color,
}}
/>
<Typography level='body-xs' ml={0.3}>
<Typography level='body-xs' ml={0.5}>
{item.name}
</Typography>
</Grid>

View File

@@ -0,0 +1,303 @@
import {
Archive,
CopyAll,
Delete,
Edit,
ManageSearch,
MoreTime,
MoreVert,
Nfc,
NoteAdd,
RecordVoiceOver,
SwitchAccessShortcut,
Unarchive,
Update,
ViewCarousel,
} from '@mui/icons-material'
import { Divider, IconButton, Menu, MenuItem } from '@mui/joy'
import React, { useEffect } from 'react'
import { useNavigate } from 'react-router-dom'
import { useError } from '../../service/ErrorProvider'
import {
ArchiveChore,
DeleteChore,
SkipChore,
UnArchiveChore,
} from '../../utils/Fetcher'
const ChoreActionMenu = ({
chore,
onChoreUpdate,
onChoreRemove,
onCompleteWithNote,
onCompleteWithPastDate,
onChangeAssignee,
onChangeDueDate,
onWriteNFC,
onDelete,
sx = {},
variant = 'soft',
}) => {
const [anchorEl, setAnchorEl] = React.useState(null)
const menuRef = React.useRef(null)
const navigate = useNavigate()
const { showError } = useError()
useEffect(() => {
const handleMenuOutsideClick = event => {
if (
anchorEl &&
!anchorEl.contains(event.target) &&
!menuRef.current.contains(event.target)
) {
handleMenuClose()
}
}
document.addEventListener('mousedown', handleMenuOutsideClick)
return () => {
document.removeEventListener('mousedown', handleMenuOutsideClick)
}
}, [anchorEl])
const handleMenuOpen = event => {
event.stopPropagation()
setAnchorEl(event.currentTarget)
}
const handleMenuClose = () => {
setAnchorEl(null)
}
const handleEdit = () => {
navigate(`/chores/${chore.id}/edit`)
handleMenuClose()
}
const handleClone = () => {
navigate(`/chores/${chore.id}/edit?clone=true`)
handleMenuClose()
}
const handleView = () => {
navigate(`/chores/${chore.id}`)
handleMenuClose()
}
const handleDelete = () => {
if (onDelete) {
onDelete()
} else {
// Default delete behavior
DeleteChore(chore.id).then(response => {
if (response.ok) {
onChoreRemove?.(chore)
}
})
}
handleMenuClose()
}
const handleArchive = () => {
if (chore.isActive) {
ArchiveChore(chore.id).then(response => {
if (response.ok) {
response.json().then(() => {
const newChore = { ...chore, isActive: false }
onChoreUpdate?.(newChore, 'archive')
})
}
})
} else {
UnArchiveChore(chore.id).then(response => {
if (response.ok) {
response.json().then(() => {
const newChore = { ...chore, isActive: true }
onChoreUpdate?.(newChore, 'unarchive')
})
}
})
}
handleMenuClose()
}
const handleSkip = () => {
SkipChore(chore.id)
.then(response => {
if (response.ok) {
response.json().then(data => {
const newChore = data.res
onChoreUpdate?.(newChore, 'skipped')
handleMenuClose()
})
}
})
.catch(error => {
if (error?.queued) {
showError({
title: 'Failed to update',
message: 'Request will be processed when you are online',
})
} else {
showError({
title: 'Failed to update',
message: error,
})
}
})
}
const handleHistory = () => {
navigate(`/chores/${chore.id}/history`)
handleMenuClose()
}
return (
<>
<IconButton
variant={variant}
color='success'
onClick={handleMenuOpen}
sx={{
borderRadius: '50%',
width: 25,
height: 25,
position: 'relative',
left: -10,
...sx,
}}
>
<MoreVert />
</IconButton>
<Menu
size='lg'
ref={menuRef}
anchorEl={anchorEl}
open={Boolean(anchorEl)}
onClose={handleMenuClose}
>
<MenuItem
onClick={e => {
e.stopPropagation()
onCompleteWithNote?.()
handleMenuClose()
}}
>
<NoteAdd />
Complete with note
</MenuItem>
<MenuItem
onClick={e => {
e.stopPropagation()
onCompleteWithPastDate?.()
handleMenuClose()
}}
>
<Update />
Complete in past
</MenuItem>
<MenuItem
onClick={e => {
e.stopPropagation()
handleSkip()
}}
>
<SwitchAccessShortcut />
Skip to next due date
</MenuItem>
<MenuItem
onClick={e => {
e.stopPropagation()
onChangeAssignee?.()
handleMenuClose()
}}
>
<RecordVoiceOver />
Delegate to someone else
</MenuItem>
<Divider />
<MenuItem
onClick={e => {
e.stopPropagation()
handleHistory()
}}
>
<ManageSearch />
History
</MenuItem>
<Divider />
<MenuItem
onClick={e => {
e.stopPropagation()
onChangeDueDate?.()
handleMenuClose()
}}
>
<MoreTime />
Change due date
</MenuItem>
<MenuItem
onClick={e => {
e.stopPropagation()
onWriteNFC?.()
handleMenuClose()
}}
>
<Nfc />
Write to NFC
</MenuItem>
<MenuItem
onClick={e => {
e.stopPropagation()
handleEdit()
}}
>
<Edit />
Edit
</MenuItem>
<MenuItem
onClick={e => {
e.stopPropagation()
handleClone()
}}
>
<CopyAll />
Clone
</MenuItem>
<MenuItem
onClick={e => {
e.stopPropagation()
handleView()
}}
>
<ViewCarousel />
View
</MenuItem>
<MenuItem
onClick={e => {
e.stopPropagation()
handleArchive()
}}
color='neutral'
>
{chore.isActive ? <Archive /> : <Unarchive />}
{chore.isActive ? 'Archive' : 'Unarchive'}
</MenuItem>
<Divider />
<MenuItem
onClick={e => {
e.stopPropagation()
handleDelete()
}}
color='danger'
>
<Delete />
Delete
</MenuItem>
</Menu>
</>
)
}
export default ChoreActionMenu