diff --git a/apps/web/src/components/diffs/AnnotatableCodeView.tsx b/apps/web/src/components/diffs/AnnotatableCodeView.tsx index f1ddfbbf539d..2a74f3a75585 100644 --- a/apps/web/src/components/diffs/AnnotatableCodeView.tsx +++ b/apps/web/src/components/diffs/AnnotatableCodeView.tsx @@ -8,7 +8,7 @@ import type { } from "@pierre/diffs"; import type { CodeViewHandle } from "@pierre/diffs/react"; import type { ScopedThreadRef } from "@t3tools/contracts"; -import { useCallback, useMemo, useState, type ReactNode, type Ref } from "react"; +import { useState, type ReactNode, type Ref } from "react"; import { type DraftId, useComposerDraftStore } from "~/composerDraftStore"; import { fnv1a32, resolveFileDiffPath } from "~/lib/diffRendering"; @@ -133,119 +133,105 @@ export function AnnotatableCodeView({ } | null>(null); const [draftText, setDraftText] = useState(""); - const filesByKey = useMemo(() => new Map(files.map((file) => [file.fileKey, file])), [files]); - const items = useMemo[]>( - () => - files.map(({ fileDiff, filePath, fileKey, fileVersion, collapsed }) => { - const persisted = reviewComments - .filter( - (comment) => - comment.sectionId === sectionId && - comment.filePath === filePath && - (comment.fenceLanguage ?? "diff") === "diff", - ) - .reduce((annotations, comment) => { - const range = restoreDiffReviewCommentRange(fileDiff, comment); - if (!range) return annotations; - return appendAnnotationEntry(annotations, range, { - id: comment.id, - kind: "comment", - range, - rangeLabel: comment.rangeLabel, - text: comment.text, - }); - }, []); - const annotations = - draft?.fileKey === fileKey ? [...persisted, draft.annotation] : persisted; - return { - id: fileKey, - type: "diff", - fileDiff, - annotations, - collapsed, - version: fnv1a32( - `${fileVersion}:${collapsed ? "1" : "0"}:${annotations - .flatMap((annotation) => - annotation.metadata.entries.map( - (entry) => `${entry.id}:${entry.rangeLabel}:${entry.text}`, - ), - ) - .join(":")}`, - ), - }; - }), - [draft, files, reviewComments, sectionId], - ); - - const removeEntry = useCallback( - (entryId: string) => { - setSelectedLines(null); - if (draft?.annotation.metadata.entries.some((entry) => entry.id === entryId)) { - setDraft(null); - setDraftText(""); - } else { - removeReviewComment(composerDraftTarget, entryId); - } + const filesByKey = new Map(files.map((file) => [file.fileKey, file])); + const items: CodeViewDiffItem[] = files.map( + ({ fileDiff, filePath, fileKey, fileVersion, collapsed }) => { + const persisted = reviewComments + .filter( + (comment) => + comment.sectionId === sectionId && + comment.filePath === filePath && + (comment.fenceLanguage ?? "diff") === "diff", + ) + .reduce((annotations, comment) => { + const range = restoreDiffReviewCommentRange(fileDiff, comment); + if (!range) return annotations; + return appendAnnotationEntry(annotations, range, { + id: comment.id, + kind: "comment", + range, + rangeLabel: comment.rangeLabel, + text: comment.text, + }); + }, []); + const annotations = draft?.fileKey === fileKey ? [...persisted, draft.annotation] : persisted; + return { + id: fileKey, + type: "diff", + fileDiff, + annotations, + collapsed, + version: fnv1a32( + `${fileVersion}:${collapsed ? "1" : "0"}:${annotations + .flatMap((annotation) => + annotation.metadata.entries.map( + (entry) => `${entry.id}:${entry.rangeLabel}:${entry.text}`, + ), + ) + .join(":")}`, + ), + }; }, - [composerDraftTarget, draft, removeReviewComment], ); - const submitEntry = useCallback( - (entryId: string, text: string) => { - const entry = draft?.annotation.metadata.entries.find( - (candidate) => candidate.id === entryId, - ); - const file = draft ? filesByKey.get(draft.fileKey) : undefined; - if (!entry || !file) return; - const comment = buildDiffReviewComment({ - id: entry.id, - sectionId, - sectionTitle, - filePath: file.filePath, - fileDiff: file.fileDiff, - range: entry.range, - text, - }); - if (comment) addReviewComment(composerDraftTarget, comment); - setSelectedLines(null); + const removeEntry = (entryId: string) => { + setSelectedLines(null); + if (draft?.annotation.metadata.entries.some((entry) => entry.id === entryId)) { setDraft(null); setDraftText(""); - }, - [addReviewComment, composerDraftTarget, draft, filesByKey, sectionId, sectionTitle], - ); + } else { + removeReviewComment(composerDraftTarget, entryId); + } + }; - const beginComment = useCallback( - (range: SelectedLineRange | null, context: DiffSelectionContext) => { - if (!range) return; - const item = context.item; - if (item.type !== "diff") return; - // Read from the item, not the file list, so this callback keeps its identity as - // patches arrive; the viewer re-applies its options whenever it changes. - const id = nextFileCommentId(); - const comment = buildDiffReviewComment({ - id, - sectionId, - sectionTitle, - filePath: resolveFileDiffPath(item.fileDiff), - fileDiff: item.fileDiff, - range, - text: "", - }); - if (!comment) return; - setDraftText(""); - setDraft({ - fileKey: item.id, - annotation: { - side: annotationSide(range), - lineNumber: range.end, - metadata: { - entries: [{ id, kind: "draft", range, rangeLabel: comment.rangeLabel, text: "" }], - }, + const submitEntry = (entryId: string, text: string) => { + const entry = draft?.annotation.metadata.entries.find((candidate) => candidate.id === entryId); + const file = draft ? filesByKey.get(draft.fileKey) : undefined; + if (!entry || !file) return; + const comment = buildDiffReviewComment({ + id: entry.id, + sectionId, + sectionTitle, + filePath: file.filePath, + fileDiff: file.fileDiff, + range: entry.range, + text, + }); + if (comment) addReviewComment(composerDraftTarget, comment); + setSelectedLines(null); + setDraft(null); + setDraftText(""); + }; + + const beginComment = (range: SelectedLineRange | null, context: DiffSelectionContext) => { + if (!range) return; + const item = context.item; + if (item.type !== "diff") return; + // Read from the item, not the file list, so the compiled callback keeps its identity + // as patches arrive; the viewer re-applies its options whenever it changes. + const id = nextFileCommentId(); + const comment = buildDiffReviewComment({ + id, + sectionId, + sectionTitle, + filePath: resolveFileDiffPath(item.fileDiff), + fileDiff: item.fileDiff, + range, + text: "", + }); + if (!comment) return; + setDraftText(""); + setDraft({ + fileKey: item.id, + annotation: { + side: annotationSide(range), + lineNumber: range.end, + metadata: { + entries: [{ id, kind: "draft", range, rangeLabel: comment.rangeLabel, text: "" }], }, - }); - }, - [sectionId, sectionTitle], - ); + }, + }); + }; const hasOpenComment = draft !== null; return (