Files
kandev/apps/web/hooks/domains/github/use-task-ci-options.ts
T
2026-06-20 10:05:25 +01:00

97 lines
3.6 KiB
TypeScript

"use client";
import { useCallback, useEffect, useRef } from "react";
import {
getTaskCIAutomationOptions,
updateTaskCIAutomationOptions,
} from "@/lib/api/domains/github-api";
import { useAppStore } from "@/components/state-provider";
import type { TaskCIAutomationPatch, TaskCIAutomationOptions } from "@/lib/types/github";
function errorMessage(error: unknown): string {
return error instanceof Error ? error.message : "Failed to load CI automation options.";
}
export function useTaskCIAutomationOptions(taskId: string | null) {
const refreshRequestRef = useRef<Record<string, number>>({});
const updateRequestRef = useRef<Record<string, number>>({});
const options = useAppStore((state) =>
taskId ? (state.taskCIAutomation.byTaskId[taskId] ?? null) : null,
);
const loading = useAppStore((state) =>
taskId ? Boolean(state.taskCIAutomation.loading[taskId]) : false,
);
const saving = useAppStore((state) =>
taskId ? Boolean(state.taskCIAutomation.saving[taskId]) : false,
);
const error = useAppStore((state) =>
taskId ? (state.taskCIAutomation.errors[taskId] ?? null) : null,
);
const setOptions = useAppStore((state) => state.setTaskCIAutomationOptions);
const setLoading = useAppStore((state) => state.setTaskCIAutomationLoading);
const setSaving = useAppStore((state) => state.setTaskCIAutomationSaving);
const setError = useAppStore((state) => state.setTaskCIAutomationError);
const refresh = useCallback(async (): Promise<TaskCIAutomationOptions | null> => {
if (!taskId) return null;
const requestId = (refreshRequestRef.current[taskId] ?? 0) + 1;
refreshRequestRef.current[taskId] = requestId;
setLoading(taskId, true);
setError(taskId, null);
try {
const response = await getTaskCIAutomationOptions(taskId, { cache: "no-store" });
if (refreshRequestRef.current[taskId] === requestId) {
setOptions(taskId, response);
}
return response;
} catch (err) {
if (refreshRequestRef.current[taskId] === requestId) {
setError(taskId, errorMessage(err));
}
throw err;
} finally {
if (refreshRequestRef.current[taskId] === requestId) {
setLoading(taskId, false);
}
}
}, [setError, setLoading, setOptions, taskId]);
const update = useCallback(
async (patch: TaskCIAutomationPatch): Promise<TaskCIAutomationOptions | null> => {
if (!taskId) return null;
const requestId = (updateRequestRef.current[taskId] ?? 0) + 1;
updateRequestRef.current[taskId] = requestId;
setSaving(taskId, true);
setError(taskId, null);
try {
const response = await updateTaskCIAutomationOptions(taskId, patch, { cache: "no-store" });
if (updateRequestRef.current[taskId] === requestId) {
setOptions(taskId, response);
}
return response;
} catch (err) {
if (updateRequestRef.current[taskId] === requestId) {
setError(taskId, errorMessage(err));
}
throw err;
} finally {
if (updateRequestRef.current[taskId] === requestId) {
setSaving(taskId, false);
}
}
},
[setError, setOptions, setSaving, taskId],
);
const resetPrompt = useCallback(() => update({ auto_fix_prompt_override: null }), [update]);
useEffect(() => {
if (!taskId || options || loading || error) return;
void refresh().catch(() => {
// Error state is stored for the UI; callers can retry via refresh.
});
}, [error, loading, options, refresh, taskId]);
return { options, loading, saving, error, refresh, update, resetPrompt };
}