diff --git a/src/domain/work-orders/api/work-order-board-patch-api.ts b/src/domain/work-orders/api/work-order-board-patch-api.ts new file mode 100644 index 00000000..819ddf69 --- /dev/null +++ b/src/domain/work-orders/api/work-order-board-patch-api.ts @@ -0,0 +1,81 @@ +import { API_PATHS } from "@/api/api-paths"; +import { ApiError, mapHttpStatusToMessage } from "@/api/api-error"; +import { apiRequestRaw } from "@/api/api"; +import { + BoardPatchConflictError, + BoardPatchValidationError, +} from "@/domain/work-orders/errors/board-patch-errors"; +import { mapWorkOrderTableRow } from "@/domain/work-orders/mappers/work-order-mapper"; +import type { + WorkOrderBoardPatchPayload, + WorkOrderPocPatchPayload, +} from "@/domain/work-orders/types/work-order-board"; +import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row"; + +/** Shared request/error handling for board row PATCH endpoints (board + poc). */ +async function patchBoardRow( + operationName: string, + method: "patch", + url: string, + payload: WorkOrderBoardPatchPayload | WorkOrderPocPatchPayload, +): Promise { + const response = await apiRequestRaw( + method, + url, + { json: payload, throwHttpErrors: false }, + operationName, + ); + + let data: unknown; + try { + data = await response.json(); + } catch { + data = undefined; + } + + if (response.ok) { + return mapWorkOrderTableRow(data); + } + + const record = typeof data === "object" && data !== null ? (data as Record) : {}; + + if (response.status === 409) { + const currentStateRaw = record.currentState ?? record.CurrentState; + const currentState = currentStateRaw != null ? mapWorkOrderTableRow(currentStateRaw) : null; + throw new BoardPatchConflictError( + typeof record.message === "string" + ? record.message + : "The record was modified by another user. Refresh and retry.", + currentState, + ); + } + + if (response.status === 422) { + throw new BoardPatchValidationError( + typeof record.code === "string" ? record.code : "ValidationError", + typeof record.message === "string" ? record.message : mapHttpStatusToMessage(422, data), + ); + } + + throw new ApiError(mapHttpStatusToMessage(response.status, data), response.status); +} + +export const workOrderBoardPatchApi = { + patchBoardField: async ( + id: string | number, + payload: WorkOrderBoardPatchPayload, + ): Promise => + patchBoardRow( + "workOrdersApi.patchBoardField", + "patch", + API_PATHS.workOrder.boardPatch(id), + payload, + ), + + /** Manual POC override — same row/error contract as the board patch. */ + updatePoc: async ( + id: string | number, + payload: WorkOrderPocPatchPayload, + ): Promise => + patchBoardRow("workOrdersApi.updatePoc", "patch", API_PATHS.workOrder.pocPatch(id), payload), +}; diff --git a/src/domain/work-orders/api/work-orders-api.ts b/src/domain/work-orders/api/work-orders-api.ts index fb02637a..35669740 100644 --- a/src/domain/work-orders/api/work-orders-api.ts +++ b/src/domain/work-orders/api/work-orders-api.ts @@ -1,12 +1,8 @@ import { API_PATHS } from "@/api/api-paths"; -import { ApiError, mapHttpStatusToMessage } from "@/api/api-error"; -import { apiDelete, apiGet, apiPost, apiPostForm, apiPut, apiRequestRaw } from "@/api/api"; +import { apiDelete, apiGet, apiPost, apiPostForm, apiPut } from "@/api/api"; import { handleApiResponse, handlePaginatedResponse } from "@/api/handle-api-response"; -import { - BoardPatchConflictError, - BoardPatchValidationError, -} from "@/domain/work-orders/errors/board-patch-errors"; import { workOrderBoardDocumentsApi } from "@/domain/work-orders/api/work-order-board-documents-api"; +import { workOrderBoardPatchApi } from "@/domain/work-orders/api/work-order-board-patch-api"; import { mapDispatchComment, mapDispatchDetail, @@ -20,7 +16,6 @@ import { mapWorkOrderDetail, mapWorkOrderFormToCreatePayload, mapWorkOrderFormToUpdateFormData, - mapWorkOrderTableRow, mapWorkOrderTableRows, } from "@/domain/work-orders/mappers/work-order-mapper"; import { mapWizardDraftToBoardCreatePayload } from "@/domain/work-orders/mappers/work-order-board-mapper"; @@ -42,11 +37,9 @@ import type { import type { WorkOrderWizardDraft } from "@/domain/work-orders/types/work-order-wizard"; import type { WorkOrderBoardListResult, - WorkOrderBoardPatchPayload, WorkOrderBoardQueryParams, WorkOrderBoardResponseApi, WorkOrderBoardSearchQueryParams, - WorkOrderPocPatchPayload, } from "@/domain/work-orders/types/work-order-board"; import type { WorkOrderBoardDetail } from "@/domain/work-orders/types/work-order-board-detail"; import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row"; @@ -142,54 +135,6 @@ function mapUser(raw: unknown): WorkOrderUser { }; } -/** Shared request/error handling for board row PATCH endpoints (board + poc). */ -async function patchBoardRow( - operationName: string, - method: "patch", - url: string, - payload: WorkOrderBoardPatchPayload | WorkOrderPocPatchPayload, -): Promise { - const response = await apiRequestRaw( - method, - url, - { json: payload, throwHttpErrors: false }, - operationName, - ); - - let data: unknown; - try { - data = await response.json(); - } catch { - data = undefined; - } - - if (response.ok) { - return mapWorkOrderTableRow(data); - } - - const record = typeof data === "object" && data !== null ? (data as Record) : {}; - - if (response.status === 409) { - const currentStateRaw = record.currentState ?? record.CurrentState; - const currentState = currentStateRaw != null ? mapWorkOrderTableRow(currentStateRaw) : null; - throw new BoardPatchConflictError( - typeof record.message === "string" - ? record.message - : "The record was modified by another user. Refresh and retry.", - currentState, - ); - } - - if (response.status === 422) { - throw new BoardPatchValidationError( - typeof record.code === "string" ? record.code : "ValidationError", - typeof record.message === "string" ? record.message : mapHttpStatusToMessage(422, data), - ); - } - - throw new ApiError(mapHttpStatusToMessage(response.status, data), response.status); -} - export const workOrdersApi = { ...workOrderBoardDocumentsApi, @@ -359,23 +304,10 @@ export const workOrdersApi = { return mapWorkOrderDetail(handleApiResponse(data)); }, - patchBoardField: async ( - id: string | number, - payload: WorkOrderBoardPatchPayload, - ): Promise => - patchBoardRow( - "workOrdersApi.patchBoardField", - "patch", - API_PATHS.workOrder.boardPatch(id), - payload, - ), + patchBoardField: workOrderBoardPatchApi.patchBoardField, /** Manual POC override — same row/error contract as the board patch. */ - updatePoc: async ( - id: string | number, - payload: WorkOrderPocPatchPayload, - ): Promise => - patchBoardRow("workOrdersApi.updatePoc", "patch", API_PATHS.workOrder.pocPatch(id), payload), + updatePoc: workOrderBoardPatchApi.updatePoc, update: async ( id: string | number,