Show ability to undo task on choreView

https://github.com/donetick/donetick/issues/505
This commit is contained in:
Mo Tarbin
2026-02-09 23:18:45 -05:00
parent 25676cff8c
commit 1b57be1d64

View File

@@ -1,7 +1,6 @@
import { import {
Archive, Archive,
CalendarMonth, CalendarMonth,
CancelScheduleSend,
Check, Check,
Checklist, Checklist,
CloseFullscreen, CloseFullscreen,
@@ -35,7 +34,6 @@ import {
MenuButton, MenuButton,
MenuItem, MenuItem,
Sheet, Sheet,
Snackbar,
Typography, Typography,
} from '@mui/joy' } from '@mui/joy'
import { Divider } from '@mui/material' import { Divider } from '@mui/material'
@@ -54,6 +52,7 @@ import {
useStartChore, useStartChore,
} from '../../queries/TimeQueries' } from '../../queries/TimeQueries'
import { useCircleMembers, useUserProfile } from '../../queries/UserQueries.jsx' import { useCircleMembers, useUserProfile } from '../../queries/UserQueries.jsx'
import { useNotification } from '../../service/NotificationProvider'
import { ChoreStatus, notInCompletionWindow } from '../../utils/Chores.jsx' import { ChoreStatus, notInCompletionWindow } from '../../utils/Chores.jsx'
import { getTextColorFromBackgroundColor } from '../../utils/Colors.jsx' import { getTextColorFromBackgroundColor } from '../../utils/Colors.jsx'
import { import {
@@ -63,6 +62,7 @@ import {
RejectChore, RejectChore,
SkipChore, SkipChore,
UnArchiveChore, UnArchiveChore,
UndoChoreAction,
UpdateChorePriority, UpdateChorePriority,
} from '../../utils/Fetcher' } from '../../utils/Fetcher'
import Priorities from '../../utils/Priorities' import Priorities from '../../utils/Priorities'
@@ -82,12 +82,11 @@ const ChoreView = () => {
const { choreId } = useParams() const { choreId } = useParams()
const [note, setNote] = useState(null) const [note, setNote] = useState(null)
const queryClient = useQueryClient() const queryClient = useQueryClient()
const { showSuccess, showError, showUndo } = useNotification()
const [searchParams] = useSearchParams() const [searchParams] = useSearchParams()
const [isPendingCompletion, setIsPendingCompletion] = useState(false)
const [timeoutId, setTimeoutId] = useState(null) const [timeoutId, setTimeoutId] = useState(null)
const [secondsLeftToCancel, setSecondsLeftToCancel] = useState(null)
const [completedDate, setCompletedDate] = useState(null) const [completedDate, setCompletedDate] = useState(null)
const [confirmModelConfig, setConfirmModelConfig] = useState({ const [confirmModelConfig, setConfirmModelConfig] = useState({
isOpen: false, isOpen: false,
@@ -189,20 +188,7 @@ const ChoreView = () => {
setInfoCards(cards) setInfoCards(cards)
} }
const handleTaskCompletion = () => { const handleTaskCompletion = () => {
setIsPendingCompletion(true) let id = setTimeout(() => {
let seconds = 3 // Starting countdown from 3 seconds
setSecondsLeftToCancel(seconds)
const countdownInterval = setInterval(() => {
seconds -= 1
setSecondsLeftToCancel(seconds)
if (seconds <= 0) {
clearInterval(countdownInterval) // Stop the countdown when it reaches 0
}
}, 1000)
const id = setTimeout(() => {
MarkChoreComplete( MarkChoreComplete(
choreId, choreId,
impersonatedUser impersonatedUser
@@ -220,11 +206,8 @@ const ChoreView = () => {
} }
}) })
.then(() => { .then(() => {
setIsPendingCompletion(false)
clearTimeout(id) clearTimeout(id)
clearInterval(countdownInterval) // Ensure to clear this interval as well
setTimeoutId(null) setTimeoutId(null)
setSecondsLeftToCancel(null)
// Invalidate chores cache to refetch data // Invalidate chores cache to refetch data
queryClient.invalidateQueries(['chores']) queryClient.invalidateQueries(['chores'])
}) })
@@ -241,6 +224,16 @@ const ChoreView = () => {
}, 3000) }, 3000)
setTimeoutId(id) setTimeoutId(id)
// Show undo notification
showSuccess({
title: 'Task Completed',
message: 'Your task has been marked as complete',
undoAction: () => {
clearTimeout(id)
setTimeoutId(null)
},
})
} }
const handleSkippingTask = () => { const handleSkippingTask = () => {
SkipChore(choreId).then(response => { SkipChore(choreId).then(response => {
@@ -250,6 +243,36 @@ const ChoreView = () => {
setChore(newChore) setChore(newChore)
// Invalidate chores cache to refetch data // Invalidate chores cache to refetch data
queryClient.invalidateQueries(['chores']) queryClient.invalidateQueries(['chores'])
// Show undo notification
showSuccess({
message: 'Task skipped',
undoAction: async () => {
try {
const undoResponse = await UndoChoreAction(choreId)
if (undoResponse.ok) {
// Refetch chore details after undo
const detailResponse = await GetChoreDetailById(choreId)
if (detailResponse.ok) {
const detailData = await detailResponse.json()
setChore(detailData.res)
queryClient.invalidateQueries(['chores'])
}
showUndo({
title: 'Undo Successful',
message: 'Task skip has been undone.',
})
} else {
throw new Error('Failed to undo')
}
} catch (error) {
showError({
title: 'Undo Failed',
message: 'Unable to undo the action. Please try again.',
})
}
},
})
}) })
} }
}) })
@@ -924,12 +947,11 @@ const ChoreView = () => {
size='lg' size='lg'
onClick={handleTaskCompletion} onClick={handleTaskCompletion}
disabled={ disabled={
isPendingCompletion ||
notInCompletionWindow(chore) || notInCompletionWindow(chore) ||
(chore.lastCompletedDate !== null && (chore.lastCompletedDate !== null &&
chore.frequencyType === 'once') chore.frequencyType === 'once')
} }
color={isPendingCompletion ? 'danger' : 'success'} color='success'
startDecorator={<Check />} startDecorator={<Check />}
sx={{ sx={{
flex: 4, flex: 4,
@@ -1017,31 +1039,6 @@ const ChoreView = () => {
</Box> </Box>
)} )}
<Snackbar
open={isPendingCompletion}
endDecorator={
<Button
onClick={() => {
if (timeoutId) {
clearTimeout(timeoutId)
setIsPendingCompletion(false)
setTimeoutId(null)
setSecondsLeftToCancel(null) // Reset or adjust as needed
}
}}
size='lg'
variant='outlined'
color='danger'
startDecorator={<CancelScheduleSend />}
>
Cancel
</Button>
}
>
<Typography level='body-md' textAlign={'center'}>
Task will be marked as completed in {secondsLeftToCancel} seconds
</Typography>
</Snackbar>
<ConfirmationModal config={confirmModelConfig} /> <ConfirmationModal config={confirmModelConfig} />
<ConfirmationModal config={timerActionConfig} /> <ConfirmationModal config={timerActionConfig} />
</Card> </Card>