import apiClient from './index.js' import { apiEndpoints as E } from './endpoints.js' import { paginatedGet } from './paginate.js' import { apiCall } from './apiError.js' /** * Drop null/undefined keys so an empty UI filter doesn't turn into * `?student_id=undefined` over the wire. */ const cleanParams = (params) => { const out = {} for (const [k, v] of Object.entries(params || {})) { if (v !== null && v !== undefined) out[k] = v } return out } /* ---------- task CRUD ---------- */ // Get all tasks with optional filters export const getTasks = (params = {}) => paginatedGet(apiClient, E.TASKS.LIST, cleanParams(params)) // Get task by id export const getTaskById = (taskId) => apiCall('GET', E.TASKS.DETAIL(taskId), null, 'Failed to fetch task detail') // Create task (spec 0004: image_* fields removed; new images go through the sub-resource) export const createTask = (data) => apiCall('POST', E.TASKS.LIST, { data }, 'Failed to create task') // Update task export const updateTask = (taskId, data) => apiCall('PATCH', E.TASKS.UPDATE(taskId), { data }, 'Failed to update task') // Delete task (spec 0004: soft-delete only; image rows are not cascade-soft-deleted) export const deleteTask = (taskId) => apiCall('DELETE', E.TASKS.DELETE(taskId), null, 'Failed to delete task') /* ---------- task image sub-resource (spec 0004) ---------- */ /** * List every image for a task (paginated; results array is flattened). * Each entry: id / mime_type / file_name / key / etag / size_bytes / audit fields. */ export const listTaskImages = (taskId, params = {}) => paginatedGet(apiClient, E.TASKS.IMAGES.LIST(taskId), cleanParams(params)) /** * Create a task image. Body shape: StdtTaskImagesWrite — * required `image_base64`, optional `mime_type` / `file_name`. The backend * enforces a soft cap of 20 images per task at POST time. */ export const createTaskImage = (taskId, payload) => apiCall('POST', E.TASKS.IMAGES.CREATE(taskId), { data: payload }, 'Failed to create task image') /** * Delete a task image. Soft-delete only — the row stays in the table and the * COS object is not removed; a refetch just hides it. */ export const deleteTaskImage = (taskId, imageId) => apiCall('DELETE', E.TASKS.IMAGES.DELETE(taskId, imageId), null, 'Failed to delete task image') /** * Fetch a task image's binary content (spec 0004 /content/ endpoint). * Must override `responseType: 'blob'` and force a wildcard Accept header; * without them DRF's JSON renderer rejects with 406. * * Returns a Blob. */ export const getTaskImageContent = (taskId, imageId) => apiCall( 'GET', E.TASKS.IMAGES.CONTENT(taskId, imageId), { config: { responseType: 'blob', headers: { Accept: '*/*' } } }, 'Failed to fetch task image content', )