import { useMutation, useQueryClient, type UseMutationResult } from "@tanstack/react-query"; import { useNavigate } from "react-router"; import { toast } from "react-toastify"; import { workOrdersApi } from "@/domain/work-orders/api/work-orders-api"; import type { WorkOrderFormSchemaValues } from "@/domain/work-orders/schemas/work-order-schema"; import type { DispatchComment, DispatchSignoff, DispatchToVendorPayload, UpdateDispatchPayload, WorkOrderComment, WorkOrderDetail, WorkOrderFormValues, WorkOrderVendorUpdatePayload, } from "@/domain/work-orders/types/work-order"; import { queryKeys } from "@/infra/query-key/query-key"; function invalidateWorkOrders(queryClient: ReturnType) { void queryClient.invalidateQueries({ queryKey: queryKeys.workOrders.all }); } interface AddWorkOrderCommentInput { text: string; commentType: "customer" | "internal"; } export interface AddDispatchCommentInput { text: string; sendEmail: boolean; } export interface UpdateChecklistItemInput { itemId: string | number; isCompleted: boolean; completedBy: string; } export interface AddDispatchSignoffInput { signoffType: string; name: string; signature: string; signatureMethod: string; } interface ChangeWorkOrderAssignmentInput { userId: string | number; userName: string; } interface UpdateWorkOrderVendorInput { vendorId: string | number; payload: WorkOrderVendorUpdatePayload; } export function useCreateWorkOrder(): UseMutationResult< WorkOrderDetail, Error, WorkOrderFormSchemaValues | WorkOrderFormValues > { const queryClient = useQueryClient(); const navigate = useNavigate(); return useMutation({ mutationFn: (values: WorkOrderFormSchemaValues | WorkOrderFormValues) => workOrdersApi.create(values), onSuccess: (data) => { invalidateWorkOrders(queryClient); toast.success("Work Order created successfully!"); navigate(`/workorders/${data.id}`); }, onError: (error: Error) => { toast.error(error.message || "Failed to create work order"); }, }); } export function useUpdateWorkOrder( id: string | number, ): UseMutationResult { const queryClient = useQueryClient(); const navigate = useNavigate(); return useMutation({ mutationFn: (values: WorkOrderFormSchemaValues | WorkOrderFormValues) => workOrdersApi.update(id, values), onSuccess: () => { invalidateWorkOrders(queryClient); void queryClient.invalidateQueries({ queryKey: queryKeys.workOrders.detail(id) }); toast.success("Work Order updated successfully!"); navigate(`/workorders/${id}`); }, onError: (error: Error) => { toast.error(error.message || "Failed to update work order"); }, }); } export function useUpdateWorkOrderVendor( workOrderId: string | number, ): UseMutationResult { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ vendorId, payload }) => workOrdersApi.updateVendorFromWorkOrder(vendorId, payload), onSuccess: () => { void queryClient.invalidateQueries({ queryKey: queryKeys.workOrders.detail(workOrderId) }); void queryClient.invalidateQueries({ queryKey: queryKeys.workOrders.all }); void queryClient.invalidateQueries({ queryKey: queryKeys.vendors.all }); toast.success("Vendor contact updated"); }, onError: (error: Error) => { toast.error(error.message || "Failed to update vendor contact"); }, }); } export function useAddWorkOrderComment( workOrderId: string | number, ): UseMutationResult { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ text, commentType }: AddWorkOrderCommentInput) => workOrdersApi.addComment(workOrderId, text, commentType), onSuccess: () => { void queryClient.invalidateQueries({ queryKey: queryKeys.workOrders.detail(workOrderId) }); }, onError: (error: Error) => { toast.error(error.message || "Failed to add comment"); }, }); } export function useChangeWorkOrderStatus( workOrderId: string | number, ): UseMutationResult { const queryClient = useQueryClient(); return useMutation({ mutationFn: (status: string) => workOrdersApi.changeStatus(workOrderId, status), onSuccess: (_data, status) => { void queryClient.invalidateQueries({ queryKey: queryKeys.workOrders.detail(workOrderId) }); invalidateWorkOrders(queryClient); toast.success(`Status changed to ${status}`); }, onError: (error: Error) => { toast.error(error.message || "Failed to update status"); }, }); } export function useChangeWorkOrderAssignment( workOrderId: string | number, ): UseMutationResult { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ userId, userName }: ChangeWorkOrderAssignmentInput) => workOrdersApi.changeAssignment(workOrderId, userId).then(() => userName), onSuccess: (userName) => { void queryClient.invalidateQueries({ queryKey: queryKeys.workOrders.detail(workOrderId) }); invalidateWorkOrders(queryClient); toast.success(`Assigned to ${userName || "Unassigned"}`); }, onError: (error: Error) => { toast.error(error.message || "Failed to update assignment"); }, }); } export function useDispatchToVendor( workOrderId: string | number, ): UseMutationResult { const queryClient = useQueryClient(); return useMutation({ mutationFn: workOrdersApi.dispatchToVendor, onSuccess: () => { void queryClient.invalidateQueries({ queryKey: queryKeys.workOrders.detail(workOrderId) }); invalidateWorkOrders(queryClient); toast.success("Dispatched successfully"); }, onError: (error: Error) => { toast.error(error.message || "Failed to dispatch"); }, }); } export function useUpdateDispatch( dispatchId: string | number, workOrderId: string | number, ): UseMutationResult { const queryClient = useQueryClient(); return useMutation({ mutationFn: workOrdersApi.updateDispatch, onSuccess: () => { void queryClient.invalidateQueries({ queryKey: queryKeys.workOrders.dispatch(dispatchId) }); void queryClient.invalidateQueries({ queryKey: queryKeys.workOrders.detail(workOrderId) }); toast.success("Dispatch updated"); }, onError: (error: Error) => { toast.error(error.message || "Failed to update dispatch"); }, }); } export function useAddDispatchComment( dispatchId: string | number, ): UseMutationResult { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ text, sendEmail }: AddDispatchCommentInput) => workOrdersApi.addDispatchComment(dispatchId, text, sendEmail), onSuccess: () => { void queryClient.invalidateQueries({ queryKey: queryKeys.workOrders.dispatch(dispatchId) }); }, onError: (error: Error) => { toast.error(error.message || "Failed to send message"); }, }); } export function useUpdateChecklistItem( dispatchId: string | number, ): UseMutationResult { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ itemId, isCompleted, completedBy }: UpdateChecklistItemInput) => workOrdersApi.updateChecklistItem(itemId, isCompleted, completedBy), onSuccess: () => { void queryClient.invalidateQueries({ queryKey: queryKeys.workOrders.dispatch(dispatchId) }); }, onError: (error: Error) => { toast.error(error.message || "Failed to update checklist item"); }, }); } export function useAddChecklistItem( dispatchId: string | number, ): UseMutationResult { const queryClient = useQueryClient(); return useMutation({ mutationFn: (itemText: string) => workOrdersApi.addChecklistItem(dispatchId, itemText), onSuccess: () => { void queryClient.invalidateQueries({ queryKey: queryKeys.workOrders.dispatch(dispatchId) }); }, onError: (error: Error) => { toast.error(error.message || "Failed to add checklist item"); }, }); } export function useAddDispatchSignoff( dispatchId: string | number, ): UseMutationResult { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ signoffType, name, signature, signatureMethod }: AddDispatchSignoffInput) => workOrdersApi.addDispatchSignoff(dispatchId, signoffType, name, signature, signatureMethod), onSuccess: (_data, variables) => { void queryClient.invalidateQueries({ queryKey: queryKeys.workOrders.dispatch(dispatchId) }); toast.success(`${variables.signoffType} sign-off collected`); }, onError: (error: Error) => { toast.error(error.message || "Failed to save sign-off"); }, }); } export function useVerifyDispatch( dispatchId: string | number, workOrderId: string | number, ): UseMutationResult { const queryClient = useQueryClient(); return useMutation({ mutationFn: () => workOrdersApi.verifyDispatch(dispatchId), onSuccess: () => { void queryClient.invalidateQueries({ queryKey: queryKeys.workOrders.dispatch(dispatchId) }); void queryClient.invalidateQueries({ queryKey: queryKeys.workOrders.detail(workOrderId) }); toast.success("Dispatch verified"); }, onError: (error: Error) => { toast.error(error.message || "Failed to verify"); }, }); }