This commit is contained in:
Marshal
2026-07-15 13:29:01 +00:00
parent c71a0043d6
commit 19c9da28ae
59 changed files with 3008 additions and 284 deletions

View File

@@ -125,12 +125,27 @@ export function useContractMutations(contractId: string) {
};
const staffAccept = useMutation({
mutationFn: (validityDays: number) =>
contractsService.staffAccept(contractId, validityDays),
mutationFn: (payload: {
validityDays: number;
documentSnapshot?: Freight.IContractDocumentSnapshot;
}) =>
contractsService.staffAccept(
contractId,
payload.validityDays,
payload.documentSnapshot,
),
onSuccess: (data) => onSuccess(data, "Contract accepted for approval"),
onError: () => toast.error("Failed to accept contract"),
});
// Edit THIS contract's document articles (per-contract; never the templates).
const updateDocument = useMutation({
mutationFn: (snapshot: Freight.IContractDocumentSnapshot) =>
contractsService.updateContractDocument(contractId, snapshot),
onSuccess: (data) => onSuccess(data, "Contract document updated"),
onError: () => toast.error("Failed to update contract document"),
});
const requestChanges = useMutation({
mutationFn: (note: string) =>
contractsService.requestChanges(contractId, note),
@@ -144,11 +159,6 @@ export function useContractMutations(contractId: string) {
onError: () => toast.error("Failed to reject contract"),
});
// Statuses that mean every approval step is done and the contract is ready to
// be generated. Once the final approval lands we generate the PDF
// automatically — staff no longer click a separate "Generate" button.
const READY_TO_GENERATE = ["APPROVED", "APPROVED_PENDING_SIGNATURE"];
const approveStep = useMutation({
mutationFn: ({
stepId,
@@ -158,25 +168,15 @@ export function useContractMutations(contractId: string) {
requiredRole: string;
}) =>
contractsService.approveStep({ id: contractId, stepId, requiredRole }),
onSuccess: async (data) => {
// If this was the LAST approval, auto-generate the contract so it goes
// straight to CONTRACT_READY without a manual step.
const alreadyGenerated = Boolean(
(data as Freight.IContract).contractGeneratedAt,
);
if (READY_TO_GENERATE.includes(data.status) && !alreadyGenerated) {
toast.success("Final approval complete — generating contract…");
try {
const generated = await contractsService.generateContract(data.id);
onSuccess(generated, "Contract generated and ready to sign");
return;
} catch {
toast.error("Approved, but contract generation failed. Retry below.");
void invalidateContractDetail(qc, data.id);
return;
}
}
onSuccess(data, "Approval step completed");
onSuccess: (data) => {
// The document is generated at the accept stage and reviewed during
// approval, so the final approval moves the contract straight to
// CONTRACT_READY on the server — no client-side generate call here.
const message =
data.status === "CONTRACT_READY"
? "Final approval complete — contract ready to sign"
: "Approval step completed";
onSuccess(data, message);
},
onError: () => toast.error("Failed to approve step"),
});
@@ -239,6 +239,7 @@ export function useContractMutations(contractId: string) {
const isPending =
staffAccept.isPending ||
updateDocument.isPending ||
requestChanges.isPending ||
reject.isPending ||
approveStep.isPending ||
@@ -249,6 +250,7 @@ export function useContractMutations(contractId: string) {
return {
staffAccept,
updateDocument,
requestChanges,
reject,
approveStep,