53 lines
2.0 KiB
TypeScript
53 lines
2.0 KiB
TypeScript
import { getConfig } from "./config";
|
|
import type { Project, Task } from "./types";
|
|
|
|
class ApiError extends Error {
|
|
constructor(public status: number, message: string) {
|
|
super(message);
|
|
}
|
|
}
|
|
|
|
async function req<T>(path: string, init?: RequestInit): Promise<T> {
|
|
const { url, token } = await getConfig();
|
|
if (!token) throw new ApiError(401, "No API token set — open Settings");
|
|
const res = await fetch(`${url}${path}`, {
|
|
...init,
|
|
headers: {
|
|
Authorization: `Bearer ${token}`,
|
|
"Content-Type": "application/json",
|
|
...init?.headers,
|
|
},
|
|
});
|
|
if (!res.ok) {
|
|
const body = await res.json().catch(() => ({ error: res.statusText }));
|
|
throw new ApiError(res.status, (body as { error?: string }).error ?? `HTTP ${res.status}`);
|
|
}
|
|
return res.json();
|
|
}
|
|
|
|
export const api = {
|
|
tasks: {
|
|
list: (params: { status?: string; project_id?: string } = {}) => {
|
|
const q = new URLSearchParams(
|
|
Object.entries(params).filter(([, v]) => v != null) as [string, string][],
|
|
).toString();
|
|
return req<Task[]>(`/v1/tasks${q ? `?${q}` : ""}`);
|
|
},
|
|
get: (id: string) => req<Task>(`/v1/tasks/${id}`),
|
|
create: (data: Partial<Task> & { title: string }) =>
|
|
req<Task>("/v1/tasks", { method: "POST", body: JSON.stringify(data) }),
|
|
update: (id: string, data: Partial<Task>) =>
|
|
req<Task>(`/v1/tasks/${id}`, { method: "PATCH", body: JSON.stringify(data) }),
|
|
trash: (id: string) => req<Task>(`/v1/tasks/${id}`, { method: "DELETE" }),
|
|
},
|
|
projects: {
|
|
list: () => req<Project[]>("/v1/projects"),
|
|
create: (data: Partial<Project> & { name: string }) =>
|
|
req<Project>("/v1/projects", { method: "POST", body: JSON.stringify(data) }),
|
|
update: (id: string, data: Partial<Project>) =>
|
|
req<Project>(`/v1/projects/${id}`, { method: "PATCH", body: JSON.stringify(data) }),
|
|
drop: (id: string) => req<Project>(`/v1/projects/${id}`, { method: "DELETE" }),
|
|
},
|
|
contexts: { list: () => req<string[]>("/v1/contexts") },
|
|
};
|