304 lines
6.5 KiB
JavaScript
304 lines
6.5 KiB
JavaScript
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
|