"use client" import type { ProjectSlugs } from "@conusai-kit/ui" import { useDataClient, useWrite } from "@conusai-kit/ui/data" // SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0 import { FormLayout, type FormValues, PageSection, ResourceList, TextField, usePageNavigation, useResourceList, } from "@conusai-kit/ui/patterns" import { useState } from "react" import type { CommentReceipt, CommentView, TaskReceipt, TaskView } from "../contract/index.js" import { describeFailure, type Labels } from "./labels.js" type Page = { rows: T[]; after?: string | undefined } export function Tasks({ slugs, seed, href, labels, timeline = false, }: { slugs: ProjectSlugs seed: Page href: string labels: Labels timeline?: boolean }) { const client = useDataClient() const { list } = useResourceList({ seed, rowId: (task) => task.taskId, read: async ({ after }) => ( await client.call>(timeline ? "activities.timeline.list" : "activities.task.list", { ...slugs, ...(after ? { after } : {}), }) ).value, }) return ( task.status === "open" ? labels.stateOpen : task.status === "done" ? labels.stateDone : labels.stateCancelled, }, ]} rowHref={(task) => `${href}/${task.taskId}`} rowLabel={(task) => task.subject} empty={{ title: labels.empty }} /> ) } export function TaskForm({ slugs, task, href, labels, }: { slugs: ProjectSlugs task?: TaskView href: string labels: Labels }) { const navigation = usePageNavigation() const [requestId] = useState(() => crypto.randomUUID()) const mutation = useWrite, TaskReceipt>( task ? "activities.task.update" : "activities.task.create", ) const submit = async ({ subject, body = "" }: FormValues) => { const result = await mutation.mutate({ ...slugs, subject, body, requestId, ...(task ? { taskId: task.taskId, expectedVersion: task.revision } : {}), }) navigation.navigate(`${href}/${result.taskId}`) } return ( describeFailure(error, labels)} submitLabel={task ? labels.update : labels.create} busyLabel={labels.busy} onSubmit={submit} > ) } export function TaskState({ slugs, task, labels }: { slugs: ProjectSlugs; task: TaskView; labels: Labels }) { const navigation = usePageNavigation() const [requestId, setRequestId] = useState(() => crypto.randomUUID()) const change = useWrite, TaskReceipt>( task.status === "done" ? "activities.task.reopen" : "activities.task.complete", ) if (task.status === "cancelled") return null const submit = async () => { await change.mutate({ ...slugs, taskId: task.taskId, expectedVersion: task.revision, requestId }) await navigation.refresh() setRequestId(crypto.randomUUID()) } return ( describeFailure(error, labels)} submitLabel={task.status === "done" ? labels.reopen : labels.complete} busyLabel={labels.busy} onSubmit={submit} /> ) } export function Comments({ slugs, task, seed, labels, }: { slugs: ProjectSlugs task: TaskView seed: Page labels: Labels }) { const client = useDataClient() const { list } = useResourceList({ seed, rowId: (comment) => comment.commentId, read: async ({ after }) => ( await client.call>("activities.comment.list", { ...slugs, taskId: task.taskId, ...(after ? { after } : {}), }) ).value, }) return ( (comment.erased ? labels.erased : comment.body), }, ]} rowLabel={(comment) => (comment.erased ? labels.erased : comment.body)} empty={{ title: labels.emptyComments }} /> ) } export function CommentForm({ slugs, task, labels }: { slugs: ProjectSlugs; task: TaskView; labels: Labels }) { const navigation = usePageNavigation() const [requestId, setRequestId] = useState(() => crypto.randomUUID()) const add = useWrite, CommentReceipt>("activities.comment.add") const submit = async ({ body = "" }: FormValues) => { await add.mutate({ ...slugs, taskId: task.taskId, expectedVersion: task.revision, requestId, body }) await navigation.refresh() setRequestId(crypto.randomUUID()) } return ( describeFailure(error, labels)} submitLabel={labels.addComment} busyLabel={labels.busy} onSubmit={submit} > ) }