shoc-frontend-new/src/domain/work-orders/use-cases/use-save-work-order.ts
Alexandre Brandizzi 45909e7aa6
Complete vendor operations roadmap frontend (#52)
* feat(vendors): complete operations roadmap frontend

* test(vendors): cover work order assignment flow

* fix(vendors): address review feedback

* fix(vendors): prevent stale preference saves

* fix(vendors): require truthful appointment bounds
2026-07-24 18:10:45 -03:00

83 lines
2.9 KiB
TypeScript

import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useNavigate } from "react-router";
import { toast } from "react-toastify";
import { vendorOperationsApi } from "@/domain/vendor-operations/api/vendor-operations-api";
import type {
VendorAssignmentPayload,
VendorAssignmentResult,
} from "@/domain/vendor-operations/types/vendor-operations";
import { workOrdersApi } from "@/domain/work-orders/api/work-orders-api";
import type { WorkOrderFormSchemaValues } from "@/domain/work-orders/schemas/work-order-schema";
import { queryKeys } from "@/infra/query-key/query-key";
type SaveWorkOrderInput = {
workOrderId?: string | number;
values: WorkOrderFormSchemaValues;
vendorAssignment?: VendorAssignmentPayload;
};
type SaveWorkOrderResult = {
workOrderId: string | number;
assignment?: VendorAssignmentResult;
};
class PartialWorkOrderSaveError extends Error {
constructor(public readonly workOrderId: string | number) {
super("Work order saved, but the vendor assignment could not be completed.");
this.name = "PartialWorkOrderSaveError";
}
}
export function useSaveWorkOrder() {
const navigate = useNavigate();
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({
workOrderId,
values,
vendorAssignment,
}: SaveWorkOrderInput): Promise<SaveWorkOrderResult> => {
const savedWorkOrder = workOrderId
? await workOrdersApi.update(workOrderId, values)
: await workOrdersApi.create(values);
let assignment: VendorAssignmentResult | undefined;
if (vendorAssignment) {
try {
assignment = await vendorOperationsApi.assignVendor(savedWorkOrder.id, vendorAssignment);
} catch {
throw new PartialWorkOrderSaveError(savedWorkOrder.id);
}
}
return { workOrderId: savedWorkOrder.id, assignment };
},
onSuccess: ({ workOrderId, assignment }) => {
void queryClient.invalidateQueries({ queryKey: queryKeys.workOrders.all });
void queryClient.invalidateQueries({
queryKey: queryKeys.workOrders.detail(workOrderId),
});
toast.success("Work order saved successfully");
if (assignment?.conflicts.length) {
const count = assignment.conflicts.length;
toast.warning(`Vendor assigned with ${count} scheduling conflict${count > 1 ? "s" : ""}.`);
}
navigate(`/workorders/${workOrderId}`);
},
onError: (error) => {
if (error instanceof PartialWorkOrderSaveError) {
void queryClient.invalidateQueries({ queryKey: queryKeys.workOrders.all });
void queryClient.invalidateQueries({
queryKey: queryKeys.workOrders.detail(error.workOrderId),
});
toast.error(error.message);
navigate(`/workorders/${error.workOrderId}`);
return;
}
toast.error("Unable to save the work order. Please try again.");
},
});
}