import { useMutation, useQueryClient } from "@tanstack/react-query"; import { toast } from "react-toastify"; import { workOrdersApi } from "@/domain/work-orders/api/work-orders-api"; import { mapApiStatusToWizard, mapWizardStatusToApi, } from "@/domain/work-orders/mappers/wizard-draft-mapper"; import { mapWorkOrderDetailToFormValues, mapWorkOrderTableRow, } from "@/domain/work-orders/mappers/work-order-mapper"; import type { WorkOrderTableRow } from "@/domain/work-orders/types/work-order-table-row"; import type { WizardWOStatus } from "@/domain/work-orders/types/work-order-wizard"; import { deriveDayFields } from "@/domain/work-orders/utils/table-day-utils"; import { enrichTableRow } from "@/domain/work-orders/utils/table-filter-utils"; import { queryKeys } from "@/infra/query-key/query-key"; export type WorkOrderTablePatch = Partial; async function loadFormAndUpdate( id: string | number, patch: ( values: ReturnType, ) => ReturnType, ) { const detail = await workOrdersApi.getById(id); const values = mapWorkOrderDetailToFormValues(detail); const next = patch(values); await workOrdersApi.update(id, next); return detail; } export function useWorkOrderTableMutations( onPatch: (id: string | number, patch: WorkOrderTablePatch) => void, ) { const queryClient = useQueryClient(); const invalidate = () => { void queryClient.invalidateQueries({ queryKey: queryKeys.workOrders.all }); }; const patchMutation = useMutation({ mutationFn: async ({ id, patch, useFullUpdate, }: { id: string | number; patch: WorkOrderTablePatch; useFullUpdate?: boolean; }) => { if (patch.status !== undefined && !useFullUpdate) { const apiStatus = mapWizardStatusToApi(patch.status as WizardWOStatus); await workOrdersApi.changeStatus(id, apiStatus); return patch; } if (patch.dispatcherId !== undefined && !useFullUpdate) { await workOrdersApi.changeAssignment(id, patch.dispatcherId || ""); return { ...patch, dispatcherName: patch.dispatcherName ?? "", }; } await loadFormAndUpdate(id, (values) => ({ ...values, workOrderNumber: patch.woNumber ?? values.workOrderNumber, internalWONumber: patch.woNumber ?? values.internalWONumber, locationId: patch.locationId != null ? String(patch.locationId) : values.locationId, dueDate: patch.dueDate ?? values.dueDate, scheduledDate: patch.scheduledOn ?? values.scheduledDate, completedDate: patch.completedDate ?? values.completedDate, assignedTo: patch.dispatcherName ?? values.assignedTo, problem: patch.pm ?? values.problem, source: patch.type ?? values.source, priority: values.priority, status: patch.status !== undefined ? mapWizardStatusToApi(patch.status as WizardWOStatus) : values.status, description: [ values.description, patch.pocNotes ? `POC notes: ${patch.pocNotes}` : "", patch.pocName || patch.pocPhone ? `POC: ${[patch.pocName, patch.pocPhone].filter(Boolean).join(" ยท ")}` : "", ] .filter(Boolean) .join("\n"), })); return patch; }, onMutate: async ({ id, patch }) => { onPatch(id, patch); }, onSuccess: () => { invalidate(); }, onError: (error: Error) => { toast.error(error.message || "Failed to update work order"); invalidate(); }, }); const patchField = (id: string | number, patch: WorkOrderTablePatch, useFullUpdate = false) => { patchMutation.mutate({ id, patch, useFullUpdate }); }; return { patchField, isPending: patchMutation.isPending, }; } export function tableRowFromDetail(detail: Awaited>) { return enrichTableRow( mapWorkOrderTableRow({ ...detail, status: mapApiStatusToWizard(detail.status), scheduledOn: detail.scheduledDate, woNumber: detail.internalWONumber || detail.workOrderNumber, dispatcherName: detail.assignedTo, pm: detail.problem, type: detail.source, }), ); } export function maybeAutoSchedulePatch(row: WorkOrderTableRow): WorkOrderTablePatch { const hasDate = !!row.scheduledOn; const hasDispatcher = !!row.dispatcherId; if (hasDate && hasDispatcher && row.status === "Incomplete") { return { status: "Scheduled" }; } return {}; } export function applySchedulePatch( scheduledOn: string, scheduleWeekOnly: boolean, ): WorkOrderTablePatch { if (scheduleWeekOnly) { return { scheduledOn: "", targetWeek: scheduledOn, scheduleWeekOnly: true, ...deriveDayFields(""), }; } return { scheduledOn, scheduleWeekOnly: false, targetWeek: "", ...deriveDayFields(scheduledOn), }; }