209 lines
5.5 KiB
TypeScript
209 lines
5.5 KiB
TypeScript
import { useState } from 'react'
|
|
import { Button, Group, Modal, Textarea } from '@pikku/mantine/core'
|
|
import { useDisclosure } from '@mantine/hooks'
|
|
import { notifications } from '@mantine/notifications'
|
|
import { m } from '@/i18n/messages'
|
|
import { useQueryClient } from '@tanstack/react-query'
|
|
import { usePikkuMutation } from '@perauset/functions-sdk/pikku/api.gen'
|
|
|
|
interface TaskActionsProps {
|
|
taskId: string
|
|
status: string
|
|
}
|
|
|
|
export function TaskActions({ taskId, status }: TaskActionsProps) {
|
|
const queryClient = useQueryClient()
|
|
const [blockOpened, { open: openBlock, close: closeBlock }] = useDisclosure()
|
|
const [blockReason, setBlockReason] = useState('')
|
|
const [completeOpened, { open: openComplete, close: closeComplete }] =
|
|
useDisclosure()
|
|
const [completeNotes, setCompleteNotes] = useState('')
|
|
|
|
// Tasks appear under several listing queries (listTasks, listMyTasks, …);
|
|
// invalidate any task-related query after a mutation.
|
|
const invalidateTasks = () => {
|
|
queryClient.invalidateQueries({
|
|
predicate: (q) =>
|
|
typeof q.queryKey[0] === 'string' &&
|
|
(q.queryKey[0] as string).toLowerCase().includes('task'),
|
|
})
|
|
}
|
|
|
|
const onError = (err: Error) => {
|
|
notifications.show({
|
|
title: m.common_error(),
|
|
message: err.message ?? 'Something went wrong',
|
|
color: 'red',
|
|
})
|
|
}
|
|
|
|
const claimMutation = usePikkuMutation('claimTask', {
|
|
onSuccess: () => {
|
|
notifications.show({
|
|
title: m.common_success(),
|
|
message: m.tasks_claimed(),
|
|
color: 'teal',
|
|
})
|
|
invalidateTasks()
|
|
},
|
|
onError,
|
|
})
|
|
|
|
const startMutation = usePikkuMutation('startTask', {
|
|
onSuccess: () => {
|
|
notifications.show({
|
|
title: m.common_success(),
|
|
message: m.tasks_started(),
|
|
color: 'teal',
|
|
})
|
|
invalidateTasks()
|
|
},
|
|
onError,
|
|
})
|
|
|
|
const completeMutation = usePikkuMutation('completeTask', {
|
|
onSuccess: () => {
|
|
notifications.show({
|
|
title: m.common_success(),
|
|
message: m.tasks_completed(),
|
|
color: 'teal',
|
|
})
|
|
closeComplete()
|
|
setCompleteNotes('')
|
|
invalidateTasks()
|
|
},
|
|
onError,
|
|
})
|
|
|
|
const blockMutation = usePikkuMutation('markTaskBlocked', {
|
|
onSuccess: () => {
|
|
notifications.show({
|
|
title: m.common_success(),
|
|
message: m.tasks_blocked(),
|
|
color: 'teal',
|
|
})
|
|
closeBlock()
|
|
setBlockReason('')
|
|
invalidateTasks()
|
|
},
|
|
onError,
|
|
})
|
|
|
|
return (
|
|
<>
|
|
<Group gap="xs" wrap="nowrap">
|
|
{status === 'open' && (
|
|
<Button
|
|
size="xs"
|
|
variant="filled"
|
|
color="teal"
|
|
loading={claimMutation.isPending}
|
|
onClick={() => claimMutation.mutate({ taskId })}
|
|
>
|
|
{m.tasks_claim()}
|
|
</Button>
|
|
)}
|
|
{status === 'assigned' && (
|
|
<Button
|
|
size="xs"
|
|
variant="filled"
|
|
color="blue"
|
|
loading={startMutation.isPending}
|
|
onClick={() => startMutation.mutate({ taskId })}
|
|
>
|
|
{m.tasks_start()}
|
|
</Button>
|
|
)}
|
|
{status === 'in_progress' && (
|
|
<Button
|
|
size="xs"
|
|
variant="filled"
|
|
color="green"
|
|
loading={completeMutation.isPending}
|
|
onClick={openComplete}
|
|
>
|
|
{m.tasks_complete()}
|
|
</Button>
|
|
)}
|
|
{(status === 'open' ||
|
|
status === 'assigned' ||
|
|
status === 'in_progress') && (
|
|
<Button
|
|
size="xs"
|
|
variant="light"
|
|
color="red"
|
|
loading={blockMutation.isPending}
|
|
onClick={openBlock}
|
|
>
|
|
{m.tasks_block()}
|
|
</Button>
|
|
)}
|
|
</Group>
|
|
|
|
<Modal
|
|
opened={blockOpened}
|
|
onClose={closeBlock}
|
|
title={m.tasks_block_title()}
|
|
centered
|
|
>
|
|
<Textarea
|
|
label={m.tasks_reason()}
|
|
placeholder={m.tasks_reason_placeholder()}
|
|
value={blockReason}
|
|
onChange={(e) => setBlockReason(e.currentTarget.value)}
|
|
minRows={3}
|
|
mb="md"
|
|
/>
|
|
<Group justify="flex-end">
|
|
<Button variant="default" onClick={closeBlock}>
|
|
{m.common_cancel()}
|
|
</Button>
|
|
<Button
|
|
color="red"
|
|
loading={blockMutation.isPending}
|
|
onClick={() => {
|
|
if (blockReason.trim())
|
|
blockMutation.mutate({ taskId, reason: blockReason })
|
|
}}
|
|
>
|
|
{m.tasks_mark_blocked()}
|
|
</Button>
|
|
</Group>
|
|
</Modal>
|
|
|
|
<Modal
|
|
opened={completeOpened}
|
|
onClose={closeComplete}
|
|
title={m.tasks_complete_title()}
|
|
centered
|
|
>
|
|
<Textarea
|
|
label={m.tasks_notes_optional()}
|
|
placeholder={m.tasks_notes_placeholder()}
|
|
value={completeNotes}
|
|
onChange={(e) => setCompleteNotes(e.currentTarget.value)}
|
|
minRows={3}
|
|
mb="md"
|
|
/>
|
|
<Group justify="flex-end">
|
|
<Button variant="default" onClick={closeComplete}>
|
|
{m.common_cancel()}
|
|
</Button>
|
|
<Button
|
|
color="green"
|
|
loading={completeMutation.isPending}
|
|
onClick={() =>
|
|
completeMutation.mutate({
|
|
taskId,
|
|
...(completeNotes ? { notes: completeNotes } : {}),
|
|
})
|
|
}
|
|
>
|
|
{m.tasks_complete()}
|
|
</Button>
|
|
</Group>
|
|
</Modal>
|
|
</>
|
|
)
|
|
}
|