work-hub-server/apps/web/app/composables/useProjectApi.ts

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 };
}