| 1 | import { useEffect, useMemo, useState } from "react"; |
| 2 | |
| 3 | import { useCommittedCommand } from "../lib/useCommittedCommand"; |
| 4 | import { desktopBridge } from "./desktopBridgeAdapter"; |
| 5 | import type { TabMeta } from "../lib/types"; |
| 6 | |
| 7 | type TopicSummary = Readonly<{ turns?: number }>; |
| 8 | |
| 9 | /** |
| 10 | * Owns the topic summary chain: the target memo keyed by topic identity, the |
| 11 | * GetTopicSummary bridge command, the single-flight fetch (an identity or |
| 12 | * revision change cancels the superseded request) and the resulting |
| 13 | * activeTopicTurns state. Presentation reads only the returned turns. |
| 14 | */ |
| 15 | export function useTopicSummary(input: { |
| 16 | activeTab: TabMeta | undefined; |
| 17 | revision: number; |
| 18 | }): { activeTopicTurns: number | undefined } { |
| 19 | const { activeTab, revision } = input; |
| 20 | const [activeTopicTurns, setActiveTopicTurns] = useState<number | undefined>(undefined); |
| 21 | |
| 22 | const scope = activeTab?.scope; |
| 23 | const workspaceRoot = activeTab?.workspaceRoot; |
| 24 | const topicId = activeTab?.topicId; |
| 25 | const target = useMemo(() => (topicId === undefined ? null : { scope, workspaceRoot, topicId }), |
| 26 | [scope, workspaceRoot, topicId]); |
| 27 | |
| 28 | const getSummary = useCommittedCommand((request: { scope: "global" | "project"; workspaceRoot: string; topicId: string }) => desktopBridge.getTopicSummary(request)); |
| 29 | const commitTurns = useCommittedCommand((turns: number | undefined) => setActiveTopicTurns(turns)); |
| 30 | |
| 31 | useEffect(() => { |
| 32 | const currentTarget = target; |
| 33 | const topicId = currentTarget?.topicId?.trim(); |
| 34 | if (!topicId) { |
| 35 | commitTurns(undefined); |
| 36 | return; |
| 37 | } |
| 38 | let current = true; |
| 39 | void getSummary({ |
| 40 | scope: currentTarget?.scope === "global" ? "global" : "project", |
| 41 | workspaceRoot: currentTarget?.scope === "global" ? "" : currentTarget?.workspaceRoot ?? "", |
| 42 | topicId, |
| 43 | }).then((summary: TopicSummary) => { |
| 44 | if (current) commitTurns(summary.turns); |
| 45 | }).catch(() => { |
| 46 | if (current) commitTurns(undefined); |
| 47 | }); |
| 48 | return () => { current = false; }; |
| 49 | }, [getSummary, commitTurns, revision, target]); |
| 50 | |
| 51 | return { activeTopicTurns }; |
| 52 | } |
| 53 |