useVersionDiff.ts2.3 KBView on GitHub /**
* Loads the selected session's markdown plus the previous session's markdown
* in parallel, then runs `diffWords` to produce segments the
* `HistoryDiffView` renders as inline coloured spans.
*
* Contract:
* - both queries are gated on the inputs being non-null.
* - when `prevToSeq` is null (i.e. the user selected the very first
* session), we return a single unchanged segment containing the
* selected markdown — there's nothing to diff against.
*/
import { useQueries } from '@tanstack/react-query';
import { diffWords } from 'diff';
import { useMemo } from 'react';
import { useTRPC } from '@/providers/query-provider';
export interface DiffSegment {
value: string;
added?: boolean;
removed?: boolean;
}
export interface UseVersionDiffResult {
segments: DiffSegment[] | null;
selectedMarkdown: string | null;
previousMarkdown: string | null;
isLoading: boolean;
error: unknown;
}
export function useVersionDiff(
documentId: string | null | undefined,
selectedToSeq: number | null,
prevToSeq: number | null,
): UseVersionDiffResult {
const trpc = useTRPC();
const [selectedQ, prevQ] = useQueries({
queries: [
{
...trpc.documents.versionContent.queryOptions({
documentId: documentId ?? '',
seq: selectedToSeq ?? 0,
}),
enabled: !!documentId && selectedToSeq !== null,
},
{
...trpc.documents.versionContent.queryOptions({
documentId: documentId ?? '',
seq: prevToSeq ?? 0,
}),
enabled: !!documentId && prevToSeq !== null,
},
],
});
const selectedMarkdown = selectedQ.data?.markdown ?? null;
const previousMarkdown = prevQ.data?.markdown ?? null;
const segments = useMemo<DiffSegment[] | null>(() => {
if (selectedMarkdown == null) return null;
if (prevToSeq === null) {
return [{ value: selectedMarkdown }];
}
if (previousMarkdown == null) return null;
return diffWords(previousMarkdown, selectedMarkdown) as DiffSegment[];
}, [selectedMarkdown, previousMarkdown, prevToSeq]);
const isLoading =
selectedQ.isLoading || (prevToSeq !== null && prevQ.isLoading);
return {
segments,
selectedMarkdown,
previousMarkdown,
isLoading,
error: selectedQ.error ?? prevQ.error ?? null,
};
}