From 75f30e20541ad40f7909b1a4da9a636935dd80f6 Mon Sep 17 00:00:00 2001 From: Marshal Date: Tue, 7 Jul 2026 08:46:31 +0000 Subject: [PATCH 1/2] Add reject step functionality to contract approval process - Implemented rejection handling in ContractApprovalStepsCard with a modal for rejection reasons. - Updated useContractMutations to include rejectStep mutation. - Added REJECT_STEP URL constant for API integration. - Enhanced ContractClearanceDetailPage to utilize linkedBookingId for improved booking handling. --- .../contracts/ContractApprovalStepsCard.tsx | 115 ++++++++++++++++-- .../backoffice/src/constants/URLS.ts | 2 + .../src/hooks/contracts/useContracts.ts | 11 ++ .../contracts/ContractClearanceDetailPage.tsx | 9 +- .../src/services/contracts.service.ts | 10 ++ 5 files changed, 134 insertions(+), 13 deletions(-) diff --git a/apps/edr-freight-web/backoffice/src/components/contracts/ContractApprovalStepsCard.tsx b/apps/edr-freight-web/backoffice/src/components/contracts/ContractApprovalStepsCard.tsx index 0d7adc5be..044c729ee 100644 --- a/apps/edr-freight-web/backoffice/src/components/contracts/ContractApprovalStepsCard.tsx +++ b/apps/edr-freight-web/backoffice/src/components/contracts/ContractApprovalStepsCard.tsx @@ -1,5 +1,5 @@ import { useMemo, useState } from "react"; -import { Check, ShieldCheck } from "lucide-react"; +import { Check, ShieldCheck, X } from "lucide-react"; import { Stack, Group, @@ -8,6 +8,7 @@ import { Button, Box, Modal, + Textarea, } from "@mantine/core"; import type { Freight } from "@edr/types"; @@ -30,6 +31,10 @@ export function ContractApprovalStepsCard({ const [confirmOpen, setConfirmOpen] = useState(false); const [pendingStep, setPendingStep] = useState(null); + const [rejectOpen, setRejectOpen] = useState(false); + const [rejectStepRow, setRejectStepRow] = + useState(null); + const [rejectReason, setRejectReason] = useState(""); const steps = useMemo( () => @@ -60,6 +65,28 @@ export function ContractApprovalStepsCard({ ); }; + const openReject = (step: Freight.IContractApprovalStep) => { + setRejectStepRow(step); + setRejectReason(""); + setRejectOpen(true); + }; + + const closeReject = () => { + setRejectOpen(false); + setRejectStepRow(null); + setRejectReason(""); + }; + + const trimmedReason = rejectReason.trim(); + + const runReject = () => { + if (!rejectStepRow || !trimmedReason) return; + mutations.rejectStep.mutate( + { stepId: rejectStepRow.id, reason: trimmedReason }, + { onSuccess: () => closeReject() }, + ); + }; + const subtitle = summary.detail || (nextPending @@ -106,8 +133,12 @@ export function ContractApprovalStepsCard({ key={step.id} step={step} isNext={nextPending?.id === step.id} - isPending={mutations.approveStep.isPending} + isPending={ + mutations.approveStep.isPending || + mutations.rejectStep.isPending + } onApprove={() => openApprove(step)} + onReject={() => openReject(step)} /> ))} @@ -149,6 +180,54 @@ export function ContractApprovalStepsCard({ + + + + + Rejecting the{" "} + + {rejectStepRow?.requiredRole} + {" "} + step rejects contract{" "} + + {contract.reference} + {" "} + outright. The customer must create a new contract — this cannot be + undone. + +