107 lines
2.6 KiB
TypeScript
107 lines
2.6 KiB
TypeScript
import type { Project } from "@workspace/schema";
|
|
|
|
interface ApiResponse<T> {
|
|
data: T | null;
|
|
error: string | null;
|
|
}
|
|
|
|
function getBaseUrl(): string {
|
|
const config = useRuntimeConfig();
|
|
return config.public.apiBaseUrl as string;
|
|
}
|
|
|
|
async function request<T>(path: string, options?: RequestInit): Promise<ApiResponse<T>> {
|
|
try {
|
|
const res = await fetch(`${getBaseUrl()}${path}`, {
|
|
headers: { "Content-Type": "application/json" },
|
|
...options,
|
|
});
|
|
|
|
if (!res.ok) {
|
|
const body = await res.json().catch(() => null);
|
|
return { data: null, error: body?.message ?? `HTTP ${res.status}` };
|
|
}
|
|
|
|
const data = (await res.json()) as T;
|
|
return { data, error: null };
|
|
} catch (err) {
|
|
return { data: null, error: err instanceof Error ? err.message : "Unknown error" };
|
|
}
|
|
}
|
|
|
|
export function useProjectApi() {
|
|
const NOT_FOUND = -1;
|
|
|
|
const projects = ref<Project[]>([]);
|
|
const loading = ref(false);
|
|
const error = ref<string | null>(null);
|
|
|
|
async function fetchProjects(): Promise<void> {
|
|
loading.value = true;
|
|
error.value = null;
|
|
|
|
const { data, error: err } = await request<Project[]>("/projects");
|
|
if (data) projects.value = data;
|
|
else error.value = err;
|
|
|
|
loading.value = false;
|
|
}
|
|
|
|
async function createProject(body: Record<string, unknown>): Promise<Project | null> {
|
|
loading.value = true;
|
|
error.value = null;
|
|
|
|
const { data, error: err } = await request<Project>("/projects", {
|
|
method: "POST",
|
|
body: JSON.stringify(body),
|
|
});
|
|
|
|
if (data) {
|
|
projects.value.push(data);
|
|
} else {
|
|
error.value = err;
|
|
}
|
|
|
|
loading.value = false;
|
|
return data;
|
|
}
|
|
|
|
async function updateProject(id: string, body: Record<string, unknown>): Promise<Project | null> {
|
|
loading.value = true;
|
|
error.value = null;
|
|
|
|
const { data, error: err } = await request<Project>(`/projects/${id}`, {
|
|
method: "PATCH",
|
|
body: JSON.stringify(body),
|
|
});
|
|
|
|
if (data) {
|
|
const idx = projects.value.findIndex(p => p.id === id);
|
|
if (idx !== NOT_FOUND) projects.value[idx] = data;
|
|
} else {
|
|
error.value = err;
|
|
}
|
|
|
|
loading.value = false;
|
|
return data;
|
|
}
|
|
|
|
async function deleteProject(id: string): Promise<boolean> {
|
|
loading.value = true;
|
|
error.value = null;
|
|
|
|
const { error: err } = await request(`/projects/${id}`, { method: "DELETE" });
|
|
|
|
if (err) {
|
|
error.value = err;
|
|
} else {
|
|
projects.value = projects.value.filter(p => p.id !== id);
|
|
}
|
|
|
|
loading.value = false;
|
|
return !err;
|
|
}
|
|
|
|
return { projects, loading, error, fetchProjects, createProject, updateProject, deleteProject };
|
|
}
|