Files
perauset-e2e-mrg0et1k/apps/app/src/components/task-actions.tsx
2026-07-11 08:54:43 +02:00

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>
</>
)
}