const API_BASE = typeof window !== "undefined" ? "" : (process.env.NEXT_PUBLIC_API_URL || "http://localhost:3000"); interface ApiOptions { method?: string; body?: unknown; token?: string; } async function apiFetch(path: string, opts: ApiOptions = {}): Promise { const headers: Record = { "Content-Type": "application/json", }; if (opts.token) { headers["Authorization"] = `Bearer ${opts.token}`; } const url = `${API_BASE}${path}`; const res = await fetch(url, { method: opts.method || "GET", headers, body: opts.body ? JSON.stringify(opts.body) : undefined, cache: "no-store", }); if (!res.ok) { const err = await res.json().catch(() => ({ message: res.statusText })); throw new Error(err.message || err.error || `HTTP ${res.status}`); } if (res.status === 204 || res.headers.get("content-length") === "0") { return {} as T; } return res.json(); } // Auth export function register(data: { email: string; name: string; phone?: string }) { return apiFetch<{ token: string; user: User }>("/api/v1/auth/register", { method: "POST", body: data, }); } export function login(data: { email: string; password?: string }) { return apiFetch<{ token: string; user: User }>("/api/v1/auth/login", { method: "POST", body: data, }); } export function getMe(token: string) { return apiFetch<{ user: User }>("/api/v1/auth/me", { token }); } // Tasks export function getTasks(token: string, params?: Record) { const qs = params ? "?" + new URLSearchParams(params).toString() : ""; return apiFetch<{ data: Task[]; total: number }>(`/api/v1/tasks${qs}`, { token }); } export function getTask(token: string, id: string) { return apiFetch(`/api/v1/tasks/${id}`, { token }); } export function createTask(token: string, data: Partial) { return apiFetch("/api/v1/tasks", { method: "POST", body: data, token }); } export function updateTask(token: string, id: string, data: Partial) { return apiFetch(`/api/v1/tasks/${id}`, { method: "PUT", body: data, token }); } export function deleteTask(token: string, id: string) { return apiFetch(`/api/v1/tasks/${id}`, { method: "DELETE", token }); } // Groups export function getGroups(token: string) { return apiFetch<{ data: Group[] }>("/api/v1/groups", { token }); } export function createGroup(token: string, data: Partial) { return apiFetch("/api/v1/groups", { method: "POST", body: data, token }); } export function updateGroup(token: string, id: string, data: Partial) { return apiFetch(`/api/v1/groups/${id}`, { method: "PUT", body: data, token }); } export function deleteGroup(token: string, id: string) { return apiFetch(`/api/v1/groups/${id}`, { method: "DELETE", token }); } export function reorderGroups(token: string, ids: string[]) { return apiFetch("/api/v1/groups/reorder", { method: "PUT", body: { ids }, token }); } // Connectors export function getConnectors(token: string) { return apiFetch<{ data: Connector[] }>("/api/v1/connectors", { token }); } export function createConnector(token: string, data: Partial) { return apiFetch("/api/v1/connectors", { method: "POST", body: data, token }); } // Types export interface User { id: string; email: string; name: string; phone?: string; } export interface Task { id: string; user_id: string | null; group_id: string | null; title: string; description: string; status: "pending" | "in_progress" | "done" | "cancelled"; priority: "low" | "medium" | "high" | "urgent"; scheduled_at: string | null; due_at: string | null; completed_at: string | null; assigned_to: string[]; attachments: string[]; external_id: string | null; external_source: string | null; created_at: string; updated_at: string; group_name: string | null; group_color: string | null; group_icon: string | null; } export interface Group { id: string; name: string; color: string; icon: string | null; sort_order: number; } export interface Connector { id: string; name: string; type: string; config: Record; }