import { useEffect, useMemo, useState } from "react"; import { useNavigate } from "react-router-dom"; import { useQuery } from "@tanstack/react-query"; import { Anchor, Button, Modal, Select, Stack, Text, Textarea, } from "@mantine/core"; import { Check, FileSignature, MessageSquareWarning, ShieldCheck, Sparkles, XCircle, Zap, } from "lucide-react"; import type { Freight } from "@edr/types"; import { api } from "@/services/api"; import { SectionCard } from "@/components/bookings/detail/SectionCard"; import type { useContractMutations } from "@/hooks/contracts/useContracts"; /** Dropdown-settings code holding the admin-configured contract validity days. */ const CONTRACT_VALIDITY_PERIODS_CODE = "contract_validity_periods"; type Mutations = ReturnType; interface ContractActionsToolbarProps { contract: Freight.IContract; mutations: Mutations; /** Switch the detail page to its Clearance Review tab. */ onReviewClearance?: () => void; } // Contract is in the pre-booking clearance phase — staff can review the // customer's uploaded documents. const CLEARANCE_REVIEW_STATUSES = [ "AWAITING_CLEARANCE_DOCUMENTS", "CLEARANCE_UNDER_REVIEW", "CLEARANCE_READY_FOR_BOOKING", ]; /** Detail-page staff actions: accept / request changes / reject / generate / sign. */ export function ContractActionsToolbar({ contract, mutations, onReviewClearance, }: ContractActionsToolbarProps) { const navigate = useNavigate(); const { status } = contract; const [acceptOpen, setAcceptOpen] = useState(false); const [validityDays, setValidityDays] = useState(null); const [changesOpen, setChangesOpen] = useState(false); const [changesNote, setChangesNote] = useState(""); const [rejectOpen, setRejectOpen] = useState(false); const [rejectReason, setRejectReason] = useState(""); // Admin-configured validity durations (days) for the accept dialog. Staff can // only pick one of these — no free-typing. Read-only setting, fetched once. const { data: validitySetting, isLoading: validityLoading } = useQuery({ ...api.dropdownSettings.getByCode.queryOptions({ input: { code: CONTRACT_VALIDITY_PERIODS_CODE }, }), retry: false, }); const validityOptions = useMemo( () => [...(validitySetting?.children ?? [])] .sort((a, b) => (a.order ?? 0) - (b.order ?? 0)) .map((o) => ({ value: String(o.value), label: o.label })), [validitySetting], ); // Default the selection to the first configured option when the dialog opens. useEffect(() => { if (acceptOpen && !validityDays && validityOptions.length > 0) { setValidityDays(validityOptions[0].value); } }, [acceptOpen, validityDays, validityOptions]); if (["REJECTED", "CANCELLED", "EXPIRED", "CONTRACT_CLOSED"].includes(status)) { return null; } if (status === "CHANGES_REQUESTED") { return ( No staff actions until the customer resubmits the contract. ); } const canAccept = status === "SUBMITTED"; // Generation only becomes available once EVERY approval step is complete and // the contract reaches APPROVED. While any step is still pending the contract // stays in PENDING_APPROVAL, so this button does not appear after only the // first (line-staff) approval — the director step must land first. const needsManualGenerate = status === "APPROVED" && !contract.contractGeneratedAt; // Signing now happens on the contract VIEW page (staff must open and read the // generated contract before signing) — no sign button in this toolbar. const canViewContract = ["CONTRACT_READY", "SIGNED_CUSTOMER"].includes(status) && Boolean(contract.contractGeneratedAt); // Show "Review clearance" while the contract is in the document-review phase. // Reviewer = GL (Path B / customs) or Operations (Path A / no customs). const canReviewClearance = Boolean(onReviewClearance) && CLEARANCE_REVIEW_STATUSES.includes(status); const clearanceReviewer = contract.customsClearingEnabled ? "Review clearance (GL)" : "Review clearance (Ops)"; return ( Confirm each step before it is applied. {canAccept && ( <> )} {needsManualGenerate && ( )} {canViewContract && ( )} {canReviewClearance && ( )} {/* GL "Create booking" removed for now — clearance ends at finalize and the customer creates the booking in the portal. */} {!canAccept && !needsManualGenerate && !canViewContract && !canReviewClearance && ( No staff actions available for this status. Monitor until the workflow advances. )} {/* Accept — sets the contract validity window */} setAcceptOpen(false)} title="Accept contract for approval" centered > Pick the contract validity window, then start the approval chain. {validityOptions.length > 0 ? (