import type { List, Task, TaskDetail, TaskItem, TaskComment, AppConfig, AppStatus, Category, Project, ProjectDetail } from './types' const BASE = '/tasks/api' async function request(path: string, opts: RequestInit = {}): Promise { const res = await fetch(`${BASE}${path}`, { credentials: 'include', headers: { 'Content-Type': 'application/json', ...opts.headers }, ...opts, }) if (res.status === 401) { ;(window.top ?? window).location.href = '/login' throw new Error('Unauthenticated') } if (!res.ok) { const err = await res.json().catch(() => ({ error: res.statusText })) throw new Error(err.error || `Request failed: ${res.status}`) } if (res.status === 204) return undefined as T return res.json() } // ── Lists ──────────────────────────────────────────────────── export function fetchLists(includeArchived = false): Promise { return request(`/lists${includeArchived ? '?archived=1' : ''}`) } export function createList(body: { name: string; colour?: string; icon?: string }): Promise { return request('/lists', { method: 'POST', body: JSON.stringify(body) }) } export function updateList(id: number, body: Partial): Promise { return request(`/lists/${id}`, { method: 'PATCH', body: JSON.stringify(body) }) } export function deleteList(id: number): Promise<{ ok: boolean }> { return request(`/lists/${id}`, { method: 'DELETE' }) } // ── Tasks ──────────────────────────────────────────────────── export interface TaskFilters { list_id?: number view?: 'today' | 'assigned' | 'shared' | 'all' status?: string category_id?: number project_id?: number } export function fetchTasks(params: TaskFilters = {}): Promise { const qs = new URLSearchParams() for (const [k, v] of Object.entries(params)) if (v !== undefined) qs.set(k, String(v)) const s = qs.toString() return request(`/tasks${s ? `?${s}` : ''}`) } export function fetchTask(id: number): Promise { return request(`/tasks/${id}`) } export function createTask(body: Record): Promise { return request('/tasks', { method: 'POST', body: JSON.stringify(body) }) } export function updateTask(id: number, body: Record): Promise { return request(`/tasks/${id}`, { method: 'PATCH', body: JSON.stringify(body) }) } export function deleteTask(id: number): Promise<{ ok: boolean }> { return request(`/tasks/${id}`, { method: 'DELETE' }) } export function reorderTasks(ids: number[]): Promise<{ ok: boolean }> { return request('/tasks/reorder', { method: 'POST', body: JSON.stringify({ ids }) }) } export function reallocateTask(id: number, to: string): Promise { return request(`/tasks/${id}/reallocate`, { method: 'POST', body: JSON.stringify({ to }) }) } // ── Tags (share/watch) ─────────────────────────────────────── export function tagTask(id: number, email: string): Promise<{ ok: boolean }> { return request(`/tasks/${id}/tags`, { method: 'POST', body: JSON.stringify({ email }) }) } export function untagTask(id: number, email: string): Promise<{ ok: boolean }> { return request(`/tasks/${id}/tags/${encodeURIComponent(email)}`, { method: 'DELETE' }) } // ── Statuses ───────────────────────────────────────────────── export function fetchStatuses(): Promise { return request('/statuses') } export function createStatus(body: { label: string; value: string; is_hold?: boolean }): Promise { return request('/statuses', { method: 'POST', body: JSON.stringify(body) }) } export function updateStatus(id: number, body: Partial): Promise { return request(`/statuses/${id}`, { method: 'PATCH', body: JSON.stringify(body) }) } export function deleteStatus(id: number): Promise<{ ok: boolean }> { return request(`/statuses/${id}`, { method: 'DELETE' }) } // ── Categories ─────────────────────────────────────────────── export function fetchCategories(): Promise { return request('/categories') } export function createCategory(body: { name: string; colour?: string }): Promise { return request('/categories', { method: 'POST', body: JSON.stringify(body) }) } export function updateCategory(id: number, body: Partial): Promise { return request(`/categories/${id}`, { method: 'PATCH', body: JSON.stringify(body) }) } export function deleteCategory(id: number): Promise<{ ok: boolean }> { return request(`/categories/${id}`, { method: 'DELETE' }) } // ── Projects ───────────────────────────────────────────────── export function fetchProjects(): Promise { return request('/projects') } export function fetchProject(id: number): Promise { return request(`/projects/${id}`) } export function createProject(body: { name: string; description?: string; colour?: string }): Promise { return request('/projects', { method: 'POST', body: JSON.stringify(body) }) } export function updateProject(id: number, body: Partial): Promise { return request(`/projects/${id}`, { method: 'PATCH', body: JSON.stringify(body) }) } export function deleteProject(id: number): Promise<{ ok: boolean }> { return request(`/projects/${id}`, { method: 'DELETE' }) } // ── Checklist items ────────────────────────────────────────── export function addItem(taskId: number, label: string): Promise { return request(`/tasks/${taskId}/items`, { method: 'POST', body: JSON.stringify({ label }) }) } export function updateItem(itemId: number, body: Partial): Promise { return request(`/tasks/items/${itemId}`, { method: 'PATCH', body: JSON.stringify(body) }) } export function deleteItem(itemId: number): Promise<{ ok: boolean }> { return request(`/tasks/items/${itemId}`, { method: 'DELETE' }) } // ── Comments ───────────────────────────────────────────────── export function addComment(taskId: number, body: string): Promise { return request(`/tasks/${taskId}/comments`, { method: 'POST', body: JSON.stringify({ body }) }) } // ── Config ─────────────────────────────────────────────────── export function fetchConfig(): Promise { return request('/config') } export function updateConfig(key: string, value: unknown): Promise<{ ok: boolean }> { return request(`/config/${key}`, { method: 'PUT', body: JSON.stringify({ value }) }) }