refactor: Consolidate chore action handling into ChoreActionMenu component and remove unused code from ChoreCard and CompactChoreCard
This commit is contained in:
@@ -30,7 +30,6 @@ import {
|
|||||||
MenuItem,
|
MenuItem,
|
||||||
Sheet,
|
Sheet,
|
||||||
Snackbar,
|
Snackbar,
|
||||||
styled,
|
|
||||||
Typography,
|
Typography,
|
||||||
} from '@mui/joy'
|
} from '@mui/joy'
|
||||||
import { Divider } from '@mui/material'
|
import { Divider } from '@mui/material'
|
||||||
@@ -54,16 +53,6 @@ import ConfirmationModal from '../Modals/Inputs/ConfirmationModal'
|
|||||||
import LoadingComponent from '../components/Loading.jsx'
|
import LoadingComponent from '../components/Loading.jsx'
|
||||||
import RichTextEditor from '../components/RichTextEditor.jsx'
|
import RichTextEditor from '../components/RichTextEditor.jsx'
|
||||||
import SubTasks from '../components/SubTask.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 ChoreView = () => {
|
||||||
const [chore, setChore] = useState({})
|
const [chore, setChore] = useState({})
|
||||||
|
|||||||
@@ -1,29 +1,9 @@
|
|||||||
import {
|
import {
|
||||||
Archive,
|
|
||||||
CancelScheduleSend,
|
CancelScheduleSend,
|
||||||
Check,
|
Check,
|
||||||
CopyAll,
|
|
||||||
Delete,
|
|
||||||
Edit,
|
|
||||||
HorizontalRule,
|
|
||||||
KeyboardControlKey,
|
|
||||||
KeyboardDoubleArrowUp,
|
|
||||||
LocalOffer,
|
|
||||||
ManageSearch,
|
|
||||||
MoreTime,
|
|
||||||
MoreVert,
|
|
||||||
Nfc,
|
|
||||||
NoteAdd,
|
|
||||||
PriorityHigh,
|
|
||||||
RecordVoiceOver,
|
|
||||||
Repeat,
|
Repeat,
|
||||||
Report,
|
|
||||||
SwitchAccessShortcut,
|
|
||||||
TimesOneMobiledata,
|
TimesOneMobiledata,
|
||||||
Toll,
|
Toll,
|
||||||
Unarchive,
|
|
||||||
Update,
|
|
||||||
ViewCarousel,
|
|
||||||
Webhook,
|
Webhook,
|
||||||
} from '@mui/icons-material'
|
} from '@mui/icons-material'
|
||||||
import {
|
import {
|
||||||
@@ -33,16 +13,13 @@ import {
|
|||||||
Card,
|
Card,
|
||||||
Chip,
|
Chip,
|
||||||
CircularProgress,
|
CircularProgress,
|
||||||
Divider,
|
|
||||||
Grid,
|
Grid,
|
||||||
IconButton,
|
IconButton,
|
||||||
Menu,
|
|
||||||
MenuItem,
|
|
||||||
Snackbar,
|
Snackbar,
|
||||||
Typography,
|
Typography,
|
||||||
} from '@mui/joy'
|
} from '@mui/joy'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import React, { useEffect } from 'react'
|
import React from 'react'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import { useImpersonateUser } from '../../contexts/ImpersonateUserContext.jsx'
|
import { useImpersonateUser } from '../../contexts/ImpersonateUserContext.jsx'
|
||||||
import { UserContext } from '../../contexts/UserContext'
|
import { UserContext } from '../../contexts/UserContext'
|
||||||
@@ -50,11 +27,8 @@ import { useError } from '../../service/ErrorProvider'
|
|||||||
import { notInCompletionWindow } from '../../utils/Chores.jsx'
|
import { notInCompletionWindow } from '../../utils/Chores.jsx'
|
||||||
import { getTextColorFromBackgroundColor } from '../../utils/Colors.jsx'
|
import { getTextColorFromBackgroundColor } from '../../utils/Colors.jsx'
|
||||||
import {
|
import {
|
||||||
ArchiveChore,
|
|
||||||
DeleteChore,
|
DeleteChore,
|
||||||
MarkChoreComplete,
|
MarkChoreComplete,
|
||||||
SkipChore,
|
|
||||||
UnArchiveChore,
|
|
||||||
UpdateChoreAssignee,
|
UpdateChoreAssignee,
|
||||||
UpdateDueDate,
|
UpdateDueDate,
|
||||||
} from '../../utils/Fetcher'
|
} from '../../utils/Fetcher'
|
||||||
@@ -64,17 +38,16 @@ import DateModal from '../Modals/Inputs/DateModal'
|
|||||||
import SelectModal from '../Modals/Inputs/SelectModal'
|
import SelectModal from '../Modals/Inputs/SelectModal'
|
||||||
import TextModal from '../Modals/Inputs/TextModal'
|
import TextModal from '../Modals/Inputs/TextModal'
|
||||||
import WriteNFCModal from '../Modals/Inputs/WriteNFCModal'
|
import WriteNFCModal from '../Modals/Inputs/WriteNFCModal'
|
||||||
|
import ChoreActionMenu from '../components/ChoreActionMenu'
|
||||||
const ChoreCard = ({
|
const ChoreCard = ({
|
||||||
chore,
|
chore,
|
||||||
performers,
|
performers,
|
||||||
onChoreUpdate,
|
onChoreUpdate,
|
||||||
onChoreRemove,
|
onChoreRemove,
|
||||||
userLabels,
|
|
||||||
sx,
|
sx,
|
||||||
viewOnly,
|
viewOnly,
|
||||||
onChipClick,
|
onChipClick,
|
||||||
}) => {
|
}) => {
|
||||||
const [activeUserId, setActiveUserId] = React.useState(0)
|
|
||||||
const [isChangeDueDateModalOpen, setIsChangeDueDateModalOpen] =
|
const [isChangeDueDateModalOpen, setIsChangeDueDateModalOpen] =
|
||||||
React.useState(false)
|
React.useState(false)
|
||||||
const [isCompleteWithPastDateModalOpen, setIsCompleteWithPastDateModalOpen] =
|
const [isCompleteWithPastDateModalOpen, setIsCompleteWithPastDateModalOpen] =
|
||||||
@@ -85,10 +58,7 @@ const ChoreCard = ({
|
|||||||
React.useState(false)
|
React.useState(false)
|
||||||
const [confirmModelConfig, setConfirmModelConfig] = React.useState({})
|
const [confirmModelConfig, setConfirmModelConfig] = React.useState({})
|
||||||
const [isNFCModalOpen, setIsNFCModalOpen] = React.useState(false)
|
const [isNFCModalOpen, setIsNFCModalOpen] = React.useState(false)
|
||||||
const [anchorEl, setAnchorEl] = React.useState(null)
|
|
||||||
const menuRef = React.useRef(null)
|
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const [isDisabled, setIsDisabled] = React.useState(false)
|
|
||||||
|
|
||||||
const [isPendingCompletion, setIsPendingCompletion] = React.useState(false)
|
const [isPendingCompletion, setIsPendingCompletion] = React.useState(false)
|
||||||
const [secondsLeftToCancel, setSecondsLeftToCancel] = React.useState(null)
|
const [secondsLeftToCancel, setSecondsLeftToCancel] = React.useState(null)
|
||||||
@@ -97,39 +67,7 @@ const ChoreCard = ({
|
|||||||
const { impersonatedUser } = useImpersonateUser()
|
const { impersonatedUser } = useImpersonateUser()
|
||||||
|
|
||||||
const { showError } = useError()
|
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 = () => {
|
const handleDelete = () => {
|
||||||
setConfirmModelConfig({
|
setConfirmModelConfig({
|
||||||
isOpen: true,
|
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 = () => {
|
const handleTaskCompletion = () => {
|
||||||
setIsPendingCompletion(true)
|
setIsPendingCompletion(true)
|
||||||
@@ -235,10 +149,6 @@ const ChoreCard = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleChangeDueDate = newDate => {
|
const handleChangeDueDate = newDate => {
|
||||||
if (activeUserId === null) {
|
|
||||||
alert('Please select a performer')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
UpdateDueDate(chore.id, newDate).then(response => {
|
UpdateDueDate(chore.id, newDate).then(response => {
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
response.json().then(data => {
|
response.json().then(data => {
|
||||||
@@ -250,11 +160,6 @@ const ChoreCard = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleCompleteWithPastDate = newDate => {
|
const handleCompleteWithPastDate = newDate => {
|
||||||
if (activeUserId === null) {
|
|
||||||
alert('Please select a performer')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
MarkChoreComplete(
|
MarkChoreComplete(
|
||||||
chore.id,
|
chore.id,
|
||||||
impersonatedUser ? { completedBy: impersonatedUser.userId } : null,
|
impersonatedUser ? { completedBy: impersonatedUser.userId } : null,
|
||||||
@@ -318,29 +223,6 @@ const ChoreCard = ({
|
|||||||
return 'neutral'
|
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 => {
|
const getRecurrentChipText = chore => {
|
||||||
// if chore.frequencyMetadata is type string then parse it otherwise assigned to the metadata:
|
// if chore.frequencyMetadata is type string then parse it otherwise assigned to the metadata:
|
||||||
const metadata =
|
const metadata =
|
||||||
@@ -678,135 +560,19 @@ const ChoreCard = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton
|
<ChoreActionMenu
|
||||||
// sx={{ width: 15 }}
|
chore={chore}
|
||||||
variant='soft'
|
onChoreUpdate={onChoreUpdate}
|
||||||
color='success'
|
onChoreRemove={onChoreRemove}
|
||||||
onClick={handleMenuOpen}
|
onCompleteWithNote={() => setIsCompleteWithNoteModalOpen(true)}
|
||||||
sx={{
|
onCompleteWithPastDate={() =>
|
||||||
borderRadius: '50%',
|
setIsCompleteWithPastDateModalOpen(true)
|
||||||
width: 25,
|
}
|
||||||
height: 25,
|
onChangeAssignee={() => setIsChangeAssigneeModalOpen(true)}
|
||||||
position: 'relative',
|
onChangeDueDate={() => setIsChangeDueDateModalOpen(true)}
|
||||||
left: -10,
|
onWriteNFC={() => setIsNFCModalOpen(true)}
|
||||||
}}
|
onDelete={handleDelete}
|
||||||
>
|
/>
|
||||||
<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>
|
|
||||||
</Box>
|
</Box>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -1,22 +1,8 @@
|
|||||||
import {
|
import {
|
||||||
Archive,
|
|
||||||
CancelScheduleSend,
|
CancelScheduleSend,
|
||||||
Check,
|
Check,
|
||||||
CopyAll,
|
|
||||||
Delete,
|
|
||||||
Edit,
|
|
||||||
ManageSearch,
|
|
||||||
MoreTime,
|
|
||||||
MoreVert,
|
|
||||||
Nfc,
|
|
||||||
NoteAdd,
|
|
||||||
RecordVoiceOver,
|
|
||||||
Repeat,
|
Repeat,
|
||||||
SwitchAccessShortcut,
|
|
||||||
TimesOneMobiledata,
|
TimesOneMobiledata,
|
||||||
Unarchive,
|
|
||||||
Update,
|
|
||||||
ViewCarousel,
|
|
||||||
Webhook,
|
Webhook,
|
||||||
} from '@mui/icons-material'
|
} from '@mui/icons-material'
|
||||||
import {
|
import {
|
||||||
@@ -24,15 +10,12 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
Chip,
|
Chip,
|
||||||
CircularProgress,
|
CircularProgress,
|
||||||
Divider,
|
|
||||||
IconButton,
|
IconButton,
|
||||||
Menu,
|
|
||||||
MenuItem,
|
|
||||||
Snackbar,
|
Snackbar,
|
||||||
Typography,
|
Typography,
|
||||||
} from '@mui/joy'
|
} from '@mui/joy'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import React, { useEffect } from 'react'
|
import React from 'react'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import { useImpersonateUser } from '../../contexts/ImpersonateUserContext.jsx'
|
import { useImpersonateUser } from '../../contexts/ImpersonateUserContext.jsx'
|
||||||
import { UserContext } from '../../contexts/UserContext'
|
import { UserContext } from '../../contexts/UserContext'
|
||||||
@@ -40,11 +23,8 @@ import { useError } from '../../service/ErrorProvider'
|
|||||||
import { notInCompletionWindow } from '../../utils/Chores.jsx'
|
import { notInCompletionWindow } from '../../utils/Chores.jsx'
|
||||||
import { getTextColorFromBackgroundColor } from '../../utils/Colors.jsx'
|
import { getTextColorFromBackgroundColor } from '../../utils/Colors.jsx'
|
||||||
import {
|
import {
|
||||||
ArchiveChore,
|
|
||||||
DeleteChore,
|
DeleteChore,
|
||||||
MarkChoreComplete,
|
MarkChoreComplete,
|
||||||
SkipChore,
|
|
||||||
UnArchiveChore,
|
|
||||||
UpdateChoreAssignee,
|
UpdateChoreAssignee,
|
||||||
UpdateDueDate,
|
UpdateDueDate,
|
||||||
} from '../../utils/Fetcher'
|
} from '../../utils/Fetcher'
|
||||||
@@ -54,6 +34,7 @@ import DateModal from '../Modals/Inputs/DateModal'
|
|||||||
import SelectModal from '../Modals/Inputs/SelectModal'
|
import SelectModal from '../Modals/Inputs/SelectModal'
|
||||||
import TextModal from '../Modals/Inputs/TextModal'
|
import TextModal from '../Modals/Inputs/TextModal'
|
||||||
import WriteNFCModal from '../Modals/Inputs/WriteNFCModal'
|
import WriteNFCModal from '../Modals/Inputs/WriteNFCModal'
|
||||||
|
import ChoreActionMenu from '../components/ChoreActionMenu'
|
||||||
|
|
||||||
const CompactChoreCard = ({
|
const CompactChoreCard = ({
|
||||||
chore,
|
chore,
|
||||||
@@ -64,7 +45,6 @@ const CompactChoreCard = ({
|
|||||||
viewOnly,
|
viewOnly,
|
||||||
onChipClick,
|
onChipClick,
|
||||||
}) => {
|
}) => {
|
||||||
const [activeUserId, setActiveUserId] = React.useState(0)
|
|
||||||
const [isChangeDueDateModalOpen, setIsChangeDueDateModalOpen] =
|
const [isChangeDueDateModalOpen, setIsChangeDueDateModalOpen] =
|
||||||
React.useState(false)
|
React.useState(false)
|
||||||
const [isCompleteWithPastDateModalOpen, setIsCompleteWithPastDateModalOpen] =
|
const [isCompleteWithPastDateModalOpen, setIsCompleteWithPastDateModalOpen] =
|
||||||
@@ -75,10 +55,7 @@ const CompactChoreCard = ({
|
|||||||
React.useState(false)
|
React.useState(false)
|
||||||
const [confirmModelConfig, setConfirmModelConfig] = React.useState({})
|
const [confirmModelConfig, setConfirmModelConfig] = React.useState({})
|
||||||
const [isNFCModalOpen, setIsNFCModalOpen] = React.useState(false)
|
const [isNFCModalOpen, setIsNFCModalOpen] = React.useState(false)
|
||||||
const [anchorEl, setAnchorEl] = React.useState(null)
|
|
||||||
const menuRef = React.useRef(null)
|
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const [isDisabled, setIsDisabled] = React.useState(false)
|
|
||||||
|
|
||||||
const [isPendingCompletion, setIsPendingCompletion] = React.useState(false)
|
const [isPendingCompletion, setIsPendingCompletion] = React.useState(false)
|
||||||
const [secondsLeftToCancel, setSecondsLeftToCancel] = React.useState(null)
|
const [secondsLeftToCancel, setSecondsLeftToCancel] = React.useState(null)
|
||||||
@@ -88,44 +65,7 @@ const CompactChoreCard = ({
|
|||||||
|
|
||||||
const { showError } = useError()
|
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)
|
// 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 = () => {
|
const handleDelete = () => {
|
||||||
setConfirmModelConfig({
|
setConfirmModelConfig({
|
||||||
isOpen: true,
|
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 = () => {
|
const handleTaskCompletion = () => {
|
||||||
setIsPendingCompletion(true)
|
setIsPendingCompletion(true)
|
||||||
let seconds = 3
|
let seconds = 3
|
||||||
@@ -230,10 +147,6 @@ const CompactChoreCard = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleChangeDueDate = newDate => {
|
const handleChangeDueDate = newDate => {
|
||||||
if (activeUserId === null) {
|
|
||||||
alert('Please select a performer')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
UpdateDueDate(chore.id, newDate).then(response => {
|
UpdateDueDate(chore.id, newDate).then(response => {
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
response.json().then(data => {
|
response.json().then(data => {
|
||||||
@@ -245,11 +158,6 @@ const CompactChoreCard = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleCompleteWithPastDate = newDate => {
|
const handleCompleteWithPastDate = newDate => {
|
||||||
if (activeUserId === null) {
|
|
||||||
alert('Please select a performer')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
MarkChoreComplete(
|
MarkChoreComplete(
|
||||||
chore.id,
|
chore.id,
|
||||||
impersonatedUser ? { completedBy: impersonatedUser.userId } : null,
|
impersonatedUser ? { completedBy: impersonatedUser.userId } : null,
|
||||||
@@ -654,113 +562,30 @@ const CompactChoreCard = ({
|
|||||||
)}
|
)}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
|
||||||
{/* Menu Button */}
|
{/* Chore Action Menu */}
|
||||||
<IconButton
|
<ChoreActionMenu
|
||||||
variant='plain'
|
variant='plain'
|
||||||
color='neutral'
|
chore={chore}
|
||||||
size='sm'
|
onChoreUpdate={onChoreUpdate}
|
||||||
onClick={e => {
|
onChoreRemove={onChoreRemove}
|
||||||
e.stopPropagation()
|
onCompleteWithNote={() => setIsCompleteWithNoteModalOpen(true)}
|
||||||
handleMenuOpen(e)
|
onCompleteWithPastDate={() =>
|
||||||
}}
|
setIsCompleteWithPastDateModalOpen(true)
|
||||||
|
}
|
||||||
|
onChangeAssignee={() => setIsChangeAssigneeModalOpen(true)}
|
||||||
|
onChangeDueDate={() => setIsChangeDueDateModalOpen(true)}
|
||||||
|
onWriteNFC={() => setIsNFCModalOpen(true)}
|
||||||
|
onDelete={handleDelete}
|
||||||
sx={{
|
sx={{
|
||||||
width: 28,
|
width: 28,
|
||||||
height: 28,
|
height: 28,
|
||||||
opacity: 0.6,
|
// opacity: 0.6,
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
/>
|
||||||
<MoreVert sx={{ fontSize: 14 }} />
|
|
||||||
</IconButton>
|
|
||||||
</Box>
|
</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>
|
</Box>
|
||||||
|
|
||||||
{/* All modals (same as original) */}
|
{/* All modals (same as original) */}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { CheckCircle, Key, Security, Smartphone } from '@mui/icons-material'
|
import { CheckCircle, Security, Smartphone } from '@mui/icons-material'
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
Box,
|
Box,
|
||||||
@@ -264,7 +264,7 @@ const MFASettings = () => {
|
|||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Card>
|
</Card>
|
||||||
|
{/*
|
||||||
{mfaEnabled && (
|
{mfaEnabled && (
|
||||||
<Card variant='outlined'>
|
<Card variant='outlined'>
|
||||||
<Box className='flex items-center justify-between'>
|
<Box className='flex items-center justify-between'>
|
||||||
@@ -288,7 +288,7 @@ const MFASettings = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
</Card>
|
</Card>
|
||||||
)}
|
)} */}
|
||||||
|
|
||||||
{/* Setup MFA Modal */}
|
{/* Setup MFA Modal */}
|
||||||
<Modal open={setupModalOpen} onClose={closeSetupModal}>
|
<Modal open={setupModalOpen} onClose={closeSetupModal}>
|
||||||
|
|||||||
@@ -122,7 +122,18 @@ const CalendarView = ({ chores }) => {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
{!selectedDate && (
|
{!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 */}
|
{/* Show legend with current user first, then other circle members who have assignments */}
|
||||||
{(() => {
|
{(() => {
|
||||||
const assignedUserIds = new Set(
|
const assignedUserIds = new Set(
|
||||||
@@ -171,7 +182,7 @@ const CalendarView = ({ chores }) => {
|
|||||||
backgroundColor: item.color,
|
backgroundColor: item.color,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Typography level='body-xs' ml={0.3}>
|
<Typography level='body-xs' ml={0.5}>
|
||||||
{item.name}
|
{item.name}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
303
src/views/components/ChoreActionMenu.jsx
Normal file
303
src/views/components/ChoreActionMenu.jsx
Normal 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
|
||||||
Reference in New Issue
Block a user