Files
edr-platform/apps/edr-freight-web/backoffice/src/hooks/bookings/useBookings.ts

168 lines
5.0 KiB
TypeScript

import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import toast from "react-hot-toast";
import { QUERY_KEYS } from "@/constants/QUERY_KEYS";
import { api } from "@/services/api";
import {
bookingsService,
type BookingListFilter,
} from "@/services/bookings.service";
import { invalidateBookingDetail } from "@/utils/queryInvalidation";
export function useBookingList(filter?: BookingListFilter, enabled = true) {
return useQuery({
queryKey: QUERY_KEYS.BOOKINGS.list(filter),
queryFn: () => bookingsService.list(filter),
enabled,
});
}
export function useBookingListSummary(filter?: BookingListFilter, enabled = true) {
return useQuery({
queryKey: QUERY_KEYS.BOOKINGS.listSummary(filter),
queryFn: () => bookingsService.getListSummary(filter),
enabled,
});
}
export function useBookingDetail(id: string | undefined) {
return useQuery({
queryKey: QUERY_KEYS.BOOKINGS.byId(id ?? ""),
queryFn: () => bookingsService.getById(id!),
enabled: Boolean(id),
});
}
export function useBookingMutations(bookingId: string) {
const qc = useQueryClient();
const onSuccess = (data: { id: string }, message: string) => {
toast.success(message);
void invalidateBookingDetail(qc, data.id);
};
const staffAccept = useMutation({
mutationFn: () => api.bookings.staffAccept.call({ id: bookingId }),
onSuccess: (data) => onSuccess(data, "Booking accepted for approval"),
onError: () => toast.error("Failed to accept booking"),
});
const requestChanges = useMutation({
mutationFn: (note: string) =>
api.bookings.requestChanges.call({ id: bookingId, note }),
onSuccess: (data) => onSuccess(data, "Changes requested from customer"),
onError: () => toast.error("Failed to request changes"),
});
const staffReject = useMutation({
mutationFn: (reason: string) =>
api.bookings.staffReject.call({ id: bookingId, reason }),
onSuccess: (data) => onSuccess(data, "Booking rejected"),
onError: () => toast.error("Failed to reject booking"),
});
const approveStep = useMutation({
mutationFn: ({
stepId,
requiredRole,
}: {
stepId: string;
requiredRole: string;
}) =>
api.bookings.approveStep.call({
id: bookingId,
stepId,
requiredRole,
}),
onSuccess: (data) => onSuccess(data, "Approval step completed"),
onError: () => toast.error("Failed to approve step"),
});
const rejectStep = useMutation({
mutationFn: ({
stepId,
reason,
}: {
stepId: string;
reason: string;
}) =>
api.bookings.rejectStep.call({
id: bookingId,
stepId,
reason,
}),
onSuccess: (data) => onSuccess(data, "Booking rejected at approval step"),
onError: () => toast.error("Failed to reject step"),
});
const generateContract = useMutation({
mutationFn: () => api.bookings.generateContract.call({ id: bookingId }),
onSuccess: (data) => onSuccess(data, "Contract generated"),
onError: () => toast.error("Failed to generate contract"),
});
const signContract = useMutation({
mutationFn: (payload: {
role: "CUSTOMER" | "STAFF";
signatureImageBase64: string;
signerDisplayName: string;
consentText?: string;
}) => bookingsService.signContract(bookingId, payload),
onSuccess: (data) => onSuccess(data, "Contract signed"),
onError: () => toast.error("Failed to sign contract"),
});
const payBooking = useMutation({
mutationFn: () => api.bookings.payBooking.call({ id: bookingId }),
onSuccess: (data) => onSuccess(data, "Payment completed"),
onError: () => toast.error("Failed to complete payment"),
});
const startTransit = useMutation({
mutationFn: () => api.bookings.startTransit.call({ id: bookingId }),
onSuccess: (data) => onSuccess(data, "Marked in transit"),
onError: () => toast.error("Failed to start transit"),
});
const complete = useMutation({
mutationFn: () => api.bookings.complete.call({ id: bookingId }),
onSuccess: (data) => onSuccess(data, "Booking completed"),
onError: () => toast.error("Failed to complete booking"),
});
const cancel = useMutation({
mutationFn: (reason: string) =>
api.bookings.cancel.call({ id: bookingId, reason }),
onSuccess: (data) => onSuccess(data, "Booking cancelled"),
onError: () => toast.error("Failed to cancel booking"),
});
const isPending =
staffAccept.isPending ||
requestChanges.isPending ||
staffReject.isPending ||
approveStep.isPending ||
rejectStep.isPending ||
generateContract.isPending ||
signContract.isPending ||
payBooking.isPending ||
startTransit.isPending ||
complete.isPending ||
cancel.isPending;
return {
staffAccept,
requestChanges,
staffReject,
approveStep,
rejectStep,
generateContract,
signContract,
payBooking,
startTransit,
complete,
cancel,
isPending,
downloadContract: () => bookingsService.downloadContract(bookingId),
};
}