42 lines
1.6 KiB
TypeScript
42 lines
1.6 KiB
TypeScript
import { useEffect } from "react";
|
|
import { useAppStore } from "@/components/state-provider";
|
|
import { getWebSocketClient } from "@/lib/ws/connection";
|
|
import { findTaskInSnapshots } from "@/lib/kanban/find-task";
|
|
import type { KanbanState } from "@/lib/state/slices";
|
|
|
|
type Task = KanbanState["tasks"][number];
|
|
|
|
export function useTask(taskId: string | null) {
|
|
// The active workflow's tasks live in `kanban.tasks`, but cross-workflow
|
|
// tasks (PR-review boards, multi-workflow swimlanes) live in
|
|
// `kanbanMulti.snapshots[*].tasks`. Mirror the lookup used by
|
|
// `KanbanWithPreview.useSelectedTask` so consumers like the chat panel
|
|
// can still resolve the task description for cross-workflow previews.
|
|
const task = useAppStore((state) => {
|
|
if (!taskId) return null;
|
|
const fromActive = state.kanban.tasks.find((item: Task) => item.id === taskId);
|
|
if (fromActive) return fromActive;
|
|
const fromSnapshot = findTaskInSnapshots(taskId, state.kanbanMulti.snapshots);
|
|
if (fromSnapshot) return fromSnapshot;
|
|
// Archived tasks leave active workflow collections but remain available in
|
|
// the sidebar cache while their history is open in Quick Chat.
|
|
return (
|
|
Object.values(state.sidebarArchivedTasks.itemsByWorkspaceId)
|
|
.flat()
|
|
.find((item: Task) => item.id === taskId) ?? null
|
|
);
|
|
});
|
|
|
|
useEffect(() => {
|
|
if (!taskId) return;
|
|
const client = getWebSocketClient();
|
|
if (!client) return;
|
|
const unsubscribe = client.subscribe(taskId);
|
|
return () => {
|
|
unsubscribe();
|
|
};
|
|
}, [taskId]);
|
|
|
|
return task;
|
|
}
|