Add typed fetch API client with 15 endpoint functions
This commit is contained in:
121
web/src/lib/api.ts
Normal file
121
web/src/lib/api.ts
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
import type {
|
||||||
|
Ticket,
|
||||||
|
Queue,
|
||||||
|
Transaction,
|
||||||
|
Scrip,
|
||||||
|
Lifecycle,
|
||||||
|
CustomField,
|
||||||
|
PreviewResult,
|
||||||
|
UpdateResult,
|
||||||
|
} from "./types";
|
||||||
|
|
||||||
|
const BASE_URL = "/api";
|
||||||
|
|
||||||
|
async function request<T>(url: string, options?: RequestInit): Promise<{ data: T | null; error: string | null }> {
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${BASE_URL}${url}`, {
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
if (!res.ok) {
|
||||||
|
const body = await res.json().catch(() => ({ error: res.statusText }));
|
||||||
|
return { data: null, error: body.error || body.message || `HTTP ${res.status}` };
|
||||||
|
}
|
||||||
|
const data = await res.json();
|
||||||
|
return { data, error: null };
|
||||||
|
} catch (err) {
|
||||||
|
return { data: null, error: err instanceof Error ? err.message : "Unknown error" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getTickets(params?: { queue_id?: string; status?: string }): Promise<{ data: Ticket[] | null; error: string | null }> {
|
||||||
|
const sp = new URLSearchParams();
|
||||||
|
if (params?.queue_id) sp.set("queue_id", params.queue_id);
|
||||||
|
if (params?.status) sp.set("status", params.status);
|
||||||
|
const qs = sp.toString();
|
||||||
|
return request<Ticket[]>(`/tickets${qs ? `?${qs}` : ""}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getTicket(id: string): Promise<{ data: Ticket | null; error: string | null }> {
|
||||||
|
return request<Ticket>(`/tickets/${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createTicket(data: { subject: string; queue_id: string }): Promise<{ data: Ticket | null; error: string | null }> {
|
||||||
|
return request<Ticket>("/tickets", { method: "POST", body: JSON.stringify(data) });
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updateTicket(id: string, data: { subject?: string; status?: string }): Promise<{ data: UpdateResult | null; error: string | null }> {
|
||||||
|
return request<UpdateResult>(`/tickets/${id}`, { method: "PATCH", body: JSON.stringify(data) });
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function previewTicket(id: string, data: { status?: string }): Promise<{ data: PreviewResult | null; error: string | null }> {
|
||||||
|
return request<PreviewResult>(`/tickets/${id}/preview`, { method: "POST", body: JSON.stringify(data) });
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getTicketTransactions(id: string): Promise<{ data: Transaction[] | null; error: string | null }> {
|
||||||
|
return request<Transaction[]>(`/tickets/${id}/transactions`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getQueues(): Promise<{ data: Queue[] | null; error: string | null }> {
|
||||||
|
return request<Queue[]>("/queues");
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createQueue(data: { name: string; description?: string }): Promise<{ data: Queue | null; error: string | null }> {
|
||||||
|
return request<Queue>("/queues", { method: "POST", body: JSON.stringify(data) });
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getScrips(): Promise<{ data: Scrip[] | null; error: string | null }> {
|
||||||
|
return request<Scrip[]>("/scrips");
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createScrip(data: {
|
||||||
|
name: string;
|
||||||
|
queue_id?: string | null;
|
||||||
|
condition_type: string;
|
||||||
|
action_type: string;
|
||||||
|
action_config?: Record<string, unknown>;
|
||||||
|
template_id?: string | null;
|
||||||
|
stage?: string;
|
||||||
|
sort_order?: number;
|
||||||
|
disabled?: boolean;
|
||||||
|
}): Promise<{ data: Scrip | null; error: string | null }> {
|
||||||
|
return request<Scrip>("/scrips", { method: "POST", body: JSON.stringify(data) });
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updateScrip(id: string, data: {
|
||||||
|
name?: string;
|
||||||
|
queue_id?: string | null;
|
||||||
|
condition_type?: string;
|
||||||
|
action_type?: string;
|
||||||
|
action_config?: Record<string, unknown>;
|
||||||
|
template_id?: string | null;
|
||||||
|
stage?: string;
|
||||||
|
sort_order?: number;
|
||||||
|
disabled?: boolean;
|
||||||
|
}): Promise<{ data: Scrip | null; error: string | null }> {
|
||||||
|
return request<Scrip>(`/scrips/${id}`, { method: "PATCH", body: JSON.stringify(data) });
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getLifecycles(): Promise<{ data: Lifecycle[] | null; error: string | null }> {
|
||||||
|
return request<Lifecycle[]>("/lifecycles");
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createLifecycle(data: {
|
||||||
|
name: string;
|
||||||
|
definition: Record<string, unknown>;
|
||||||
|
}): Promise<{ data: Lifecycle | null; error: string | null }> {
|
||||||
|
return request<Lifecycle>("/lifecycles", { method: "POST", body: JSON.stringify(data) });
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getCustomFields(): Promise<{ data: CustomField[] | null; error: string | null }> {
|
||||||
|
return request<CustomField[]>("/custom-fields");
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createCustomField(data: {
|
||||||
|
name: string;
|
||||||
|
field_type: string;
|
||||||
|
values?: unknown | null;
|
||||||
|
max_values?: number;
|
||||||
|
}): Promise<{ data: CustomField | null; error: string | null }> {
|
||||||
|
return request<CustomField>("/custom-fields", { method: "POST", body: JSON.stringify(data) });
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user