shoc-frontend-new/src/domain/work-orders/use-cases/use-work-order-table-mutations.ts

156 lines
4.9 KiB
TypeScript
Raw Normal View History

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<WorkOrderTableRow>;
async function loadFormAndUpdate(
id: string | number,
patch: (
values: ReturnType<typeof mapWorkOrderDetailToFormValues>,
) => ReturnType<typeof mapWorkOrderDetailToFormValues>,
) {
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<ReturnType<typeof workOrdersApi.getById>>) {
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),
};
}