import { APP_ID } from "../config"; const TOKEN_KEY = "zino_token"; function baseUrl(): string { return (import.meta.env.VITE_ZINO_API_URL || "").replace(/\/+$/, ""); } function headers(): Record { const h: Record = { "Content-Type": "application/json" }; const token = localStorage.getItem(TOKEN_KEY); if (token) h["Authorization"] = `Bearer ${token}`; return h; } async function request(method: string, path: string, body?: unknown): Promise { const res = await fetch(`${baseUrl()}${path}`, { method, headers: headers(), body: body ? JSON.stringify(body) : undefined, }); if (res.status === 401) { localStorage.removeItem(TOKEN_KEY); localStorage.removeItem("zino_user"); window.location.href = "/login"; throw new Error("Unauthorized"); } if (!res.ok) { let msg = res.statusText; try { const e = await res.json(); if (e.error) msg = e.error; } catch {} throw new Error(msg); } if (res.status === 204) return undefined as T; return res.json() as Promise; } // --------------------------------------------------------------------------- // Header // --------------------------------------------------------------------------- export interface HeaderConfig { slots: { left: string[]; right: string[]; center: string[] }; layout: { type: string; height: string; position: string; full_width: boolean }; components: { nav?: { items: NavItem[] }; logo?: { text?: string; image_url?: string; display_type: string }; profile?: { shape: string; show_name: boolean }; }; } export interface NavItem { id: string; icon: string; type: string; label: string; screen_uuid: string; } export async function getHeaderConfig(deviceType = "desktop"): Promise { const raw = await request("GET", `/app/${APP_ID}/view/header/${deviceType}`); return raw.config ?? raw; } // --------------------------------------------------------------------------- // Screens // --------------------------------------------------------------------------- export interface ScreenListItem { id: number; source_screen_id: number; screen_name: string; device: string; description: string; } export interface ScreenLayout { id: number; source_screen_id: number; screen_name: string; layout: LayoutElement[]; } export interface LayoutElement { type: string; style?: Record; config: Record; classes?: string[]; } export function getScreens(deviceType = "desktop"): Promise { return request("GET", `/app/${APP_ID}/view/screens?device_type=${deviceType}`); } export function getScreen(idOrUuid: number | string): Promise { return request("GET", `/app/${APP_ID}/view/screens/${idOrUuid}`); } // --------------------------------------------------------------------------- // RV Screens // --------------------------------------------------------------------------- export interface RVScreen { id: number; source_screen_id: number; screen_name: string; rv_template_uid: string; layout?: any; } // Accepts either the numeric source_screen_id OR the source_uuid — both // are accepted by the view-service's rv-screens endpoint. export function getRVScreen(idOrUuid: number | string): Promise { return request("GET", `/app/${APP_ID}/view/rv-screens/${idOrUuid}`); } // --------------------------------------------------------------------------- // Record View (POST-based) // --------------------------------------------------------------------------- export interface SearchQuery { page?: number; limit?: number; sort_by?: string; sort_dir?: "asc" | "desc"; search?: string; filters?: Array<{ field_key: string; value: string; data_type?: string }>; } export interface RecordViewField { field_key: string; output_label: string; data_type: string; is_filter: boolean; is_search: boolean; type?: string; activity_id?: string; } export interface RecordViewResponse { config: { fields: RecordViewField[] }; data: Record[]; pagination?: { page: number; limit: number; total_count: number; total_pages: number; }; } export function getRecordView( rvTemplateUid: string, rvScreenId: string | number, query: SearchQuery = {}, ): Promise { return request("POST", `/app/${APP_ID}/view/recordview`, { rv_template_uid: rvTemplateUid, rv_screen_id: String(rvScreenId), search_query: { page: query.page || 1, limit: query.limit || 50, sort_by: query.sort_by || "", sort_dir: query.sort_dir || "desc", search: query.search || "", filters: query.filters || [], }, }); } export function getRecordViewLegacy( rvUid: string, query: SearchQuery = {}, ): Promise { const qs = new URLSearchParams(); qs.set("rv_id", rvUid); if (query.page) qs.set("page", String(query.page)); if (query.limit) qs.set("limit", String(query.limit)); if (query.sort_by) qs.set("sort_by", query.sort_by); if (query.sort_dir) qs.set("sort_dir", query.sort_dir); if (query.search) qs.set("search", query.search); if (query.filters) { for (const f of query.filters) { qs.set(`filter.${f.field_key}`, f.value); } } return request("GET", `/recordview?${qs.toString()}`); } // --------------------------------------------------------------------------- // DV Screens // --------------------------------------------------------------------------- export interface DVScreen { id: number; source_screen_id: number; screen_name: string; dv_template_uid: string; layout?: any; } export function getDVScreen(idOrUuid: number | string): Promise { return request("GET", `/app/${APP_ID}/view/dv-screens/${idOrUuid}`); } // --------------------------------------------------------------------------- // Detail View // --------------------------------------------------------------------------- export interface DetailViewResponse { config: { fields: Array<{ field_key: string; output_label: string; data_type: string }> }; data: Record; } export function getDetailView(dvSourceIdOrUid: number | string, instanceId: string): Promise { return request( "GET", `/app/${APP_ID}/view/detailview/${encodeURIComponent(String(dvSourceIdOrUid))}?instance_id=${encodeURIComponent(instanceId)}`, ); } export function getDetailViewLegacy(dvUid: string, instanceId: string): Promise { return request( "GET", `/detailview?dv_id=${encodeURIComponent(dvUid)}&instance_id=${encodeURIComponent(instanceId)}`, ); } // --------------------------------------------------------------------------- // Form Screens // --------------------------------------------------------------------------- export interface FormScreenField { id: string; uid: string; name: string; type: string; data_type: string; mandatory: boolean; value?: any; properties?: { options?: Array<{ label: string; value: string }>; country_code?: string; }; } export interface FormScreenResponse { id: number; activity_uid: string; activity_name: string; device_type: string; fields: FormScreenField[]; grid_config: Array<{ i: string; x: number; y: number; w: number; h: number }>; layout: any[]; } export function getFormScreen( activityId: string, instanceId?: string, deviceType = "desktop", ): Promise { return request("POST", `/app/${APP_ID}/view/form-screens`, { activity_id: activityId, device_type: deviceType, ...(instanceId ? { instance_id: instanceId } : {}), }); } // --------------------------------------------------------------------------- // Workflow Actions // --------------------------------------------------------------------------- export interface WorkflowResponse { success: boolean; status_code?: number; message?: string; data?: Record; instance_id?: string; } // Core-service expects the workflow UUID as `workflow_uuid` — the numeric // `workflow_id` field was removed when the clone-portable identifier rolled out. export function startWorkflow( workflowUuid: string, activityId: string, data?: Record, ): Promise { return request("POST", `/app/${APP_ID}/start`, { workflow_uuid: workflowUuid, activity_id: activityId, data, }); } export function performActivity( workflowUuid: string, instanceId: string, activityId: string, data?: Record, ): Promise { return request("POST", `/app/${APP_ID}/activity`, { workflow_uuid: workflowUuid, instance_id: instanceId, activity_id: activityId, data, }); } export function submitForm( workflowUuid: string, activityId: string, formData: Record, instanceId?: string, deviceType = "desktop", ): Promise { return request("POST", `/app/${APP_ID}/form/submit`, { workflow_uuid: workflowUuid, activity_id: activityId, device_type: deviceType, form_data: formData, ...(instanceId ? { instance_id: instanceId } : {}), }); } // --------------------------------------------------------------------------- // Instance // --------------------------------------------------------------------------- export interface InstanceResponse { instance_id: string; workflow_id: string; current_state_id: string; current_state_name: string; data: Record; created_at: string; updated_at: string; } export function getInstance(workflowUuid: string, instanceId: string): Promise { return request("POST", `/app/${APP_ID}/instance`, { workflow_uuid: workflowUuid, instance_id: instanceId, }); } // --------------------------------------------------------------------------- // Audit // --------------------------------------------------------------------------- export interface AuditEntry { id: number; user_id: string; user_roles: string[]; activity_id: string; data: Record; execution_state: string; created_at: string; } export function getAuditLog(instanceId: string): Promise { return request("GET", `/app/${APP_ID}/view/audit?instance_id=${encodeURIComponent(instanceId)}`); }