Files
kandev/apps/web/hooks/domains/github/use-pr-commits.ts
T

98 lines
3.0 KiB
TypeScript

"use client";
import { useEffect, useCallback, useState, useRef } from "react";
import { useAppStore } from "@/components/state-provider";
import { getWebSocketClient } from "@/lib/ws/connection";
import type { PRCommitInfo } from "@/lib/types/github";
type PRCommitsState = {
commits: PRCommitInfo[];
loading: boolean;
error: string | null;
};
type WorkspacePRCommitsState = { workspaceId: string | null; state: PRCommitsState };
const INITIAL_STATE: PRCommitsState = {
commits: [],
loading: false,
error: null,
};
async function fetchPRCommits(
workspaceId: string,
owner: string,
repo: string,
prNumber: number,
setState: (s: PRCommitsState) => void,
) {
const client = getWebSocketClient();
if (!client) return;
setState({ commits: [], loading: true, error: null });
try {
const response = await client.request<{ commits?: PRCommitInfo[] }>("github.pr_commits.get", {
workspace_id: workspaceId,
owner,
repo,
number: prNumber,
});
setState({ commits: response?.commits ?? [], loading: false, error: null });
} catch (err) {
setState({
commits: [],
loading: false,
error: err instanceof Error ? err.message : "Failed to fetch PR commits",
});
}
}
/**
* Fetches the commits in a pull request via WebSocket.
* Returns commit metadata from the GitHub API.
*/
export function usePRCommits(
owner: string | null,
repo: string | null,
prNumber: number | null,
refreshKey?: string | null,
) {
const workspaceId = useAppStore((s) => s.workspaces.activeId);
const [result, setResult] = useState<WorkspacePRCommitsState>({
workspaceId: null,
state: INITIAL_STATE,
});
const hasParams = !!workspaceId && !!owner && !!repo && !!prNumber;
const paramsKeyRef = useRef<string>("");
const requestIdRef = useRef(0);
const refresh = useCallback(() => {
if (!workspaceId || !owner || !repo || !prNumber) return;
const requestId = ++requestIdRef.current;
void fetchPRCommits(workspaceId, owner, repo, prNumber, (next) => {
if (requestId !== requestIdRef.current) return;
setResult({ workspaceId, state: next });
});
}, [workspaceId, owner, repo, prNumber]);
useEffect(() => {
const key = hasParams ? `${workspaceId}/${owner}/${repo}/${prNumber}/${refreshKey ?? ""}` : "";
if (key === paramsKeyRef.current) return;
paramsKeyRef.current = key;
if (!workspaceId || !owner || !repo || !prNumber) {
requestIdRef.current++; // invalidate in-flight responses
return;
}
const requestId = ++requestIdRef.current;
void fetchPRCommits(workspaceId, owner, repo, prNumber, (next) => {
if (requestId !== requestIdRef.current) return;
setResult({ workspaceId, state: next });
});
}, [workspaceId, owner, repo, prNumber, hasParams, refreshKey]);
// Return initial state when params are null to clear stale data
if (!hasParams || result.workspaceId !== workspaceId) {
return { ...INITIAL_STATE, refresh };
}
return { ...result.state, refresh };
}