Merge branch 'freight_feature/contrat' of github.com:Tria-plc/edr-platform into freight_feature/contrat

This commit is contained in:
marshal
2026-06-29 00:03:01 +03:00
7 changed files with 191 additions and 219 deletions

View File

@@ -479,13 +479,19 @@ export class ContractClearanceService {
}
/**
* GL ET queue: customs (Path B) contracts awaiting pre-booking document review.
* GL ET clearance hub: every customs (Path B) contract that still needs
* customs clearance — awaiting the customer's documents, under GL review, or
* finalized and waiting for the customer to create the booking in the portal.
*/
async queue(filter: FilterContractDto): Promise<PaginatedContracts> {
return this.contractsRepository.findAllPaginated({
page: filter.page ?? 1,
pageSize: filter.pageSize ?? 100,
statuses: ['CLEARANCE_UNDER_REVIEW'],
statuses: [
'AWAITING_CLEARANCE_DOCUMENTS',
'CLEARANCE_UNDER_REVIEW',
'CLEARANCE_READY_FOR_BOOKING',
],
customsClearingEnabled: true,
sortBy: filter.sortBy,
sortOrder: filter.sortOrder,

View File

@@ -29,12 +29,12 @@ import LoginPage from "./pages/auth/LoginPage";
import BookingContractPage from "./pages/bookings/BookingContractPage";
import BookingRequestDetailPage from "./pages/bookings/BookingRequestDetailPage";
import BookingRequestsPage from "./pages/bookings/BookingRequestsPage";
import DocumentClearanceDetailPage from "./pages/bookings/DocumentClearanceDetailPage";
import DocumentClearanceListPage from "./pages/bookings/DocumentClearanceListPage";
import NewBookingPage from "./pages/bookings/NewBookingPage";
import ContractRequestsPage from "./pages/contracts/ContractRequestsPage";
import ContractRequestDetailPage from "./pages/contracts/ContractRequestDetailPage";
import ContractViewPage from "./pages/contracts/ContractViewPage";
import ContractClearanceListPage from "./pages/contracts/ContractClearanceListPage";
import ContractClearanceDetailPage from "./pages/contracts/ContractClearanceDetailPage";
import GlCreateBookingForm from "./components/contracts/GlCreateBookingForm";
import BookingMilestonesPage from "./pages/contracts/BookingMilestonesPage";
import CustomerDetailPage from "./pages/customers/CustomerDetailPage";
@@ -128,9 +128,9 @@ const buildSidebarSections = (demoItems: SidebarItem[]): SidebarSection[] => [
items: [
{
label: "Document Clearance",
href: "/dashboard/clearance",
href: "/dashboard/contracts/clearance",
icon: <ShieldCheck />,
permission: FREIGHT_PERMS.bookings.reviewDocuments,
permission: FREIGHT_PERMS.contracts.clearanceReview,
},
{
label: "Train Schedules",
@@ -409,21 +409,14 @@ const App = () => {
path="booking-requests/:id/contract"
element={<BookingContractPage />}
/>
{/* Legacy booking-based clearance URLs → the contract clearance hub. */}
<Route
path="clearance"
element={
<RequirePermission permission={FREIGHT_PERMS.bookings.reviewDocuments}>
<DocumentClearanceListPage />
</RequirePermission>
}
element={<Navigate to="/dashboard/contracts/clearance" replace />}
/>
<Route
path="clearance/:id"
element={
<RequirePermission permission={FREIGHT_PERMS.bookings.reviewDocuments}>
<DocumentClearanceDetailPage />
</RequirePermission>
}
element={<Navigate to="/dashboard/contracts/clearance" replace />}
/>
{/* Contracts (Path A/B) */}
@@ -451,17 +444,27 @@ const App = () => {
</RequirePermission>
}
/>
{/* GL (Path B) contract clearance review hub */}
<Route
path="contracts/clearance"
element={<Navigate to="/dashboard/clearance" replace />}
/>
<Route
path="contracts/ops-clearance"
element={<Navigate to="/dashboard/clearance?mode=ops" replace />}
element={
<RequirePermission permission={FREIGHT_PERMS.contracts.clearanceReview}>
<ContractClearanceListPage />
</RequirePermission>
}
/>
<Route
path="contracts/clearance/:id"
element={<Navigate to="/dashboard/clearance" replace />}
element={
<RequirePermission permission={FREIGHT_PERMS.contracts.clearanceReview}>
<ContractClearanceDetailPage />
</RequirePermission>
}
/>
{/* Path A ops queue out of scope for now → fold into the GL hub. */}
<Route
path="contracts/ops-clearance"
element={<Navigate to="/dashboard/contracts/clearance" replace />}
/>
<Route
path="contracts/:id/create-booking"

View File

@@ -112,7 +112,9 @@ export function ContractClearanceReviewSection({
);
const glDocs = useMemo(
() =>
(clearance?.documents ?? []).filter((d) => d.uploadedBy === "gl"),
(clearance?.documents ?? []).filter(
(d) => d.uploadedBy === "gl_et" || d.uploadedBy === "gl_dj",
),
[clearance],
);

View File

@@ -90,6 +90,20 @@ export default function GlCreateBookingForm() {
return [...sizes];
}, [contract?.cargoScope]);
// Bulk cargo types declared on the contract scope (prefill, no free-text).
const bulkCargoOptions = useMemo(() => {
const seen = new Map<string, string>();
(contract?.cargoScope ?? []).forEach((s) => {
if (s.containerSize || !s.cargoTypeId) return;
if (!seen.has(s.cargoTypeId)) {
seen.set(s.cargoTypeId, s.cargoFreeText?.trim() || s.cargoTypeId);
}
});
return [...seen.entries()].map(([value, label]) => ({ value, label }));
}, [contract?.cargoScope]);
const defaultBulkCargoTypeId = bulkCargoOptions[0]?.value ?? "";
if (isLoading) {
return (
<PageContainer>
@@ -105,7 +119,7 @@ export default function GlCreateBookingForm() {
<PageContainer>
<PageHeader
title="Contract not found"
backTo="/dashboard/contracts/clearance"
backTo="/dashboard/clearance"
/>
</PageContainer>
);
@@ -151,7 +165,12 @@ export default function GlCreateBookingForm() {
const addBulkLine = () =>
setBulkLines((prev) => [
...prev,
{ cargoTypeId: "", cargoWeightTons: "", itemCount: "", hazardousQuantity: "" },
{
cargoTypeId: defaultBulkCargoTypeId,
cargoWeightTons: "",
itemCount: "",
hazardousQuantity: "",
},
]);
const removeBulkLine = (idx: number) =>
setBulkLines((prev) => prev.filter((_, i) => i !== idx));
@@ -214,12 +233,12 @@ export default function GlCreateBookingForm() {
<PageHeader
title="Create booking (GL)"
subtitle={`Enter the shipment details on behalf of the customer for contract ${contract.reference}.`}
backTo={`/dashboard/contracts/clearance/${contract.id}`}
backTo={`/dashboard/clearance/${contract.id}`}
breadcrumbs={[
{ label: "Contract Clearance", href: "/dashboard/contracts/clearance" },
{ label: "Document Clearance", href: "/dashboard/clearance" },
{
label: contract.reference,
href: `/dashboard/contracts/clearance/${contract.id}`,
href: `/dashboard/clearance/${contract.id}`,
},
{ label: "Create booking" },
]}
@@ -486,14 +505,28 @@ export default function GlCreateBookingForm() {
</Group>
<Grid gap="sm">
<Grid.Col span={{ base: 12, sm: 6 }}>
<TextInput
label="Cargo type id"
placeholder="Optional"
value={line.cargoTypeId}
onChange={(e) =>
patchBulk(idx, { cargoTypeId: e.currentTarget.value })
}
/>
{bulkCargoOptions.length > 0 ? (
<Select
label="Cargo type"
placeholder="Select cargo type"
value={line.cargoTypeId || null}
onChange={(v) =>
patchBulk(idx, { cargoTypeId: v ?? "" })
}
data={bulkCargoOptions}
/>
) : (
<TextInput
label="Cargo type id"
placeholder="Optional"
value={line.cargoTypeId}
onChange={(e) =>
patchBulk(idx, {
cargoTypeId: e.currentTarget.value,
})
}
/>
)}
</Grid.Col>
<Grid.Col span={{ base: 6, sm: 6 }}>
<NumberInput
@@ -545,9 +578,7 @@ export default function GlCreateBookingForm() {
<Group justify="flex-end">
<Button
variant="default"
onClick={() =>
navigate(`/dashboard/contracts/clearance/${contract.id}`)
}
onClick={() => navigate(`/dashboard/clearance/${contract.id}`)}
>
Cancel
</Button>

View File

@@ -1,6 +1,6 @@
import { useCallback, useMemo, useState } from "react";
import { useQuery } from "@tanstack/react-query";
import { useNavigate, useSearchParams } from "react-router-dom";
import { useNavigate } from "react-router-dom";
import {
ActionIcon,
Badge,
@@ -54,7 +54,6 @@ import {
type ViewMode = "table" | "cards";
type PageTab = "queue" | "history";
type ClearanceMode = "gl" | "ops";
const CLEARANCE_REVIEW_STATUS = "DOCUMENTS_UNDER_REVIEW";
const CLEARANCE_HISTORY_STATUS = "CLEARANCE_READY";
@@ -131,12 +130,6 @@ function DirectionIcon({ direction }: { direction: string }) {
export default function DocumentClearanceListPage() {
const navigate = useNavigate();
const [searchParams, setSearchParams] = useSearchParams();
// "mode=ops" query param lets the old ops-clearance redirect land on the right tab
const initialMode: ClearanceMode =
searchParams.get("mode") === "ops" ? "ops" : "gl";
const [clearanceMode, setClearanceMode] = useState<ClearanceMode>(initialMode);
const [pageTab, setPageTab] = useState<PageTab>("queue");
const [activeTab, setActiveTab] = useState<ClearanceTabKey>("all");
const [query, setQuery] = useState("");
@@ -146,7 +139,7 @@ export default function DocumentClearanceListPage() {
const isHistory = pageTab === "history";
const { data, isLoading, isError, isFetching, refetch } = useQuery({
queryKey: ["clearance", "list", clearanceMode, isHistory],
queryKey: ["clearance", "list", isHistory],
queryFn: () =>
bookingsService.list({
status: isHistory ? CLEARANCE_HISTORY_STATUS : CLEARANCE_REVIEW_STATUS,
@@ -155,22 +148,18 @@ export default function DocumentClearanceListPage() {
});
const allRows = useMemo(() => {
const rows = (data?.items ?? []).map(toClearanceRow);
const filtered =
clearanceMode === "gl"
? rows.filter((r) => r.hasCustoms)
: rows.filter((r) => !r.hasCustoms);
// GL clearance queue: customs bookings only
const rows = (data?.items ?? []).map(toClearanceRow).filter((r) => r.hasCustoms);
if (isHistory) {
// Latest cleared first — fall back to updatedAt
return [...filtered].sort((a, b) => {
return [...rows].sort((a, b) => {
const ta = new Date(a.updatedAt || 0).getTime();
const tb = new Date(b.updatedAt || 0).getTime();
return tb - ta;
});
}
return filtered;
}, [data?.items, clearanceMode, isHistory]);
return rows;
}, [data?.items, isHistory]);
const tabCounts = useMemo(
() => ({
@@ -209,15 +198,6 @@ export default function DocumentClearanceListPage() {
[navigate],
);
const handleModeChange = (mode: ClearanceMode) => {
setClearanceMode(mode);
setPageTab("queue");
setActiveTab("all");
setPagination({ pageIndex: 0, pageSize: pagination.pageSize });
// clear the ?mode= param after first use
setSearchParams({});
};
const statusBadge = isHistory ? (
<Badge
variant="light"
@@ -302,7 +282,7 @@ export default function DocumentClearanceListPage() {
{
id: "status",
header: () => <span className={bookingTable.headerCell}>Status</span>,
cell: ({ row }) =>
cell: () =>
isHistory ? (
<Badge size="sm" variant="light" color="edr-green" radius="sm">
Cleared
@@ -347,18 +327,7 @@ export default function DocumentClearanceListPage() {
}
/>
{/* Mode toggle: GL Customs vs Self-Clearance (Operations) */}
<Group>
<SegmentedControl
value={clearanceMode}
onChange={(v) => handleModeChange(v as ClearanceMode)}
data={[
{ value: "gl", label: "GL Clearance" },
{ value: "ops", label: "Self-Clearance" },
]}
radius="md"
color="edr-green"
/>
<SegmentedControl
value={pageTab}
onChange={(v) => {

View File

@@ -21,7 +21,6 @@ import {
CheckCircle2,
Clock,
PackageCheck,
PackagePlus,
ShieldCheck,
} from "lucide-react";
@@ -32,15 +31,9 @@ import { ContractClearanceReviewSection } from "@/components/contracts/ContractC
import { QUERY_KEYS } from "@/constants/QUERY_KEYS";
import { contractsService } from "@/services/contracts.service";
import { useContractDetail } from "@/hooks/contracts/useContracts";
import { useAuth } from "@/auth/useAuth";
import { canCreateContractBooking } from "@/lib/permissions";
import { Button } from "@mantine/core";
import { useNavigate } from "react-router-dom";
export default function ContractClearanceDetailPage() {
const { id } = useParams<{ id: string }>();
const navigate = useNavigate();
const { user } = useAuth();
const { data: contract } = useContractDetail(id);
const {
@@ -66,13 +59,9 @@ export default function ContractClearanceDetailPage() {
}, [clearance]);
const reference = contract?.reference ?? "Clearance";
// Path A (no customs): Operations reviews; the customer books in the portal
// there is no "Create booking" action here.
const selfClear = clearance?.includesCustoms === false;
const canBook =
!selfClear &&
clearance?.clearanceStatus === "CLEARANCE_READY_FOR_BOOKING" &&
canCreateContractBooking(user);
// Customs (Path B) hub. The customer always creates the booking in the portal
// after GL finalizes clearance — there is no GL "Create booking" action here.
const ready = clearance?.clearanceStatus === "CLEARANCE_READY_FOR_BOOKING";
if (isLoading) {
return (
@@ -90,11 +79,11 @@ export default function ContractClearanceDetailPage() {
<PageContainer>
<PageHeader
title="Clearance not found"
backTo="/dashboard/contracts/clearance"
backTo="/dashboard/clearance"
breadcrumbs={[
{
label: "Contract Clearance",
href: "/dashboard/contracts/clearance",
label: "Document Clearance",
href: "/dashboard/clearance",
},
{ label: "Not found" },
]}
@@ -111,16 +100,25 @@ export default function ContractClearanceDetailPage() {
<Stack gap="lg">
<PageHeader
title={reference}
backTo="/dashboard/contracts/clearance"
backTo="/dashboard/clearance"
breadcrumbs={[
{
label: "Contract Clearance",
href: "/dashboard/contracts/clearance",
label: "Document Clearance",
href: "/dashboard/clearance",
},
{ label: reference },
]}
meta={
clearance.allApproved ? (
ready ? (
<Badge
variant="light"
color="edr-green"
radius="sm"
leftSection={<PackageCheck size={13} />}
>
Ready customer books
</Badge>
) : clearance.allApproved ? (
<Badge
variant="light"
color="edr-green"
@@ -140,29 +138,28 @@ export default function ContractClearanceDetailPage() {
</Badge>
)
}
action={
canBook ? (
<Button
color="edr-green"
leftSection={<PackagePlus size={16} />}
onClick={() =>
navigate(`/dashboard/contracts/${id}/create-booking`)
}
>
Create booking
</Button>
) : undefined
}
/>
<ClearanceHero contract={contract} stats={stats} />
{ready ? (
<Alert
color="edr-green"
radius="md"
icon={<PackageCheck size={16} />}
title="Clearance finalized"
>
Customs clearance is complete. The customer can now create the
shipment booking from the portal no further action is needed here.
</Alert>
) : null}
<Grid gap="lg">
<Grid.Col span={{ base: 12, lg: 8 }}>
<ContractClearanceReviewSection
contractId={id!}
hideSummary
selfClear={selfClear}
selfClear={false}
/>
</Grid.Col>

View File

@@ -15,12 +15,11 @@ import {
} from "@mantine/core";
import {
ArrowRight,
CheckCircle,
ChevronRight,
FileText,
History,
Inbox,
LayoutGrid,
PackageCheck,
RefreshCw,
Search,
ShieldCheck,
@@ -38,19 +37,11 @@ import {
} from "@edr/ui-common";
import type { Freight } from "@edr/types";
import { ContractStatusBadge } from "@/components/contracts/ContractStatusBadge";
import { PageContainer } from "@/components/page/PageContainer";
import { PageHeader } from "@/components/page/PageHeader";
import { KpiStrip } from "@/components/page/KpiStrip";
import { bookingTable } from "@/components/bookings/booking-ui.styles";
import {
useContractClearanceHistory,
useContractClearanceQueue,
useOpsClearanceHistory,
useOpsClearanceQueue,
} from "@/hooks/contracts/useContracts";
type PageTab = "queue" | "history";
import { useContractClearanceQueue } from "@/hooks/contracts/useContracts";
type ViewMode = "table" | "cards";
@@ -64,6 +55,8 @@ interface ClearanceRow {
destinationLabel: string;
contractKind: string;
status: string;
/** true once GL has finalized clearance — customer now books in the portal. */
ready: boolean;
}
function yardLabel(
@@ -92,6 +85,7 @@ function toClearanceRow(contract: Freight.IContract): ClearanceRow {
destinationLabel: yardLabel(last?.destinationYard),
contractKind: contract.contractKind,
status: contract.status,
ready: contract.status === "CLEARANCE_READY_FOR_BOOKING",
};
}
@@ -114,33 +108,46 @@ function DirectionIcon({ direction }: { direction: string }) {
);
}
function StatusBadge({ row }: { row: ClearanceRow }) {
if (row.ready) {
return (
<Tooltip
label="Clearance finalized — the customer creates the booking in the portal"
withArrow
>
<Badge
size="sm"
variant="light"
color="edr-green"
radius="sm"
leftSection={<PackageCheck size={12} />}
>
Ready customer books
</Badge>
</Tooltip>
);
}
return (
<Badge size="sm" variant="light" color="yellow" radius="sm">
Under review
</Badge>
);
}
/**
* Pre-booking clearance queue. In `opsMode` it lists Path A self-clearance
* contracts for the Operations team (non-customs); otherwise the GL ET/DJ
* customs queue (Path B). Both route to the same detail page, which detects the
* path from the contract.
* Document Clearance hub. Lists every customs (Path B) contract that still needs
* customs clearance — awaiting documents, under GL review, or finalized and
* waiting for the customer to create the booking in the portal. A single list,
* no queue/history/direction tabs.
*/
export default function ContractClearanceListPage({
opsMode = false,
}: {
opsMode?: boolean;
} = {}) {
export default function ContractClearanceListPage() {
const navigate = useNavigate();
const [query, setQuery] = useState("");
const [view, setView] = useState<ViewMode>("table");
const [pageTab, setPageTab] = useState<PageTab>("queue");
const { pagination, setPagination } = usePagination({ pageSize: 10 });
const isHistory = pageTab === "history";
const glQueue = useContractClearanceQueue(!opsMode && !isHistory);
const opsQueue = useOpsClearanceQueue(opsMode && !isHistory);
const glHistory = useContractClearanceHistory(!opsMode && isHistory);
const opsHistory = useOpsClearanceHistory(opsMode && isHistory);
const { data, isLoading, isError, isFetching, refetch } = opsMode
? (isHistory ? opsHistory : opsQueue)
: (isHistory ? glHistory : glQueue);
const { data, isLoading, isError, isFetching, refetch } =
useContractClearanceQueue(true);
const allRows = useMemo(
() => (data?.items ?? []).map(toClearanceRow),
@@ -150,8 +157,8 @@ export default function ContractClearanceListPage({
const counts = useMemo(
() => ({
all: allRows.length,
import: allRows.filter((r) => r.tradeDirection === "IMPORT").length,
export: allRows.filter((r) => r.tradeDirection === "EXPORT").length,
ready: allRows.filter((r) => r.ready).length,
review: allRows.filter((r) => !r.ready).length,
}),
[allRows],
);
@@ -177,7 +184,7 @@ export default function ContractClearanceListPage({
}, [rows, pagination.pageIndex, pagination.pageSize]);
const openDetail = useCallback(
(id: string) => navigate(`/dashboard/contracts/clearance/${id}`),
(id: string) => navigate(`/dashboard/clearance/${id}`),
[navigate],
);
@@ -244,14 +251,7 @@ export default function ContractClearanceListPage({
{
id: "status",
header: () => <span className={bookingTable.headerCell}>Status</span>,
cell: ({ row }) =>
isHistory ? (
<ContractStatusBadge status={row.original.status} />
) : (
<Badge size="sm" variant="light" color="edr-green" radius="sm">
Under review
</Badge>
),
cell: ({ row }) => <StatusBadge row={row.original} />,
},
{
id: "go",
@@ -270,20 +270,16 @@ export default function ContractClearanceListPage({
<PageContainer>
<Stack gap="lg">
<PageHeader
title={opsMode ? "Self-Clearance Review" : "Contract Clearance"}
subtitle={
opsMode
? "Review the customer's own clearance documents (no EDR customs service) before they create a shipment booking."
: "Review pre-booking clearance documents on contracts before Global Logistics creates the shipment booking."
}
title="Document Clearance"
subtitle="Review pre-booking customs documents on contracts and finalize clearance. Once finalized, the customer creates the shipment booking in the portal."
meta={
<Badge
variant="light"
color={isHistory ? "gray" : "edr-green"}
color="edr-green"
radius="sm"
leftSection={isHistory ? <History size={13} /> : <ShieldCheck size={13} />}
leftSection={<ShieldCheck size={13} />}
>
{isHistory ? `${counts.all} completed` : `${counts.all} awaiting review`}
{counts.all} need clearance
</Badge>
}
action={
@@ -300,53 +296,28 @@ export default function ContractClearanceListPage({
}
/>
<Group>
<SegmentedControl
size="sm"
radius="md"
value={pageTab}
onChange={(v) => {
setPageTab(v as PageTab);
setPagination({ pageIndex: 0, pageSize: pagination.pageSize });
}}
data={[
{
value: "queue",
label: (
<Group gap={6} wrap="nowrap">
<Inbox size={15} />
<Box visibleFrom="xs">Queue</Box>
</Group>
),
},
{
value: "history",
label: (
<Group gap={6} wrap="nowrap">
<History size={15} />
<Box visibleFrom="xs">History</Box>
</Group>
),
},
]}
/>
</Group>
<KpiStrip
loading={isLoading}
items={
isHistory
? [
{ label: "Total cleared", value: counts.all, icon: CheckCircle, color: "edr-green" },
{ label: "Import", value: counts.import, icon: Truck, color: "edr-green" },
{ label: "Export", value: counts.export, icon: ShipWheel, color: "gray" },
]
: [
{ label: "Awaiting review", value: counts.all, icon: Inbox, color: "edr-green" },
{ label: "Import", value: counts.import, icon: Truck, color: "edr-green" },
{ label: "Export", value: counts.export, icon: ShipWheel, color: "gray" },
]
}
items={[
{
label: "Need clearance",
value: counts.all,
icon: Inbox,
color: "edr-green",
},
{
label: "Awaiting review",
value: counts.review,
icon: ShieldCheck,
color: "yellow",
},
{
label: "Ready — customer books",
value: counts.ready,
icon: PackageCheck,
color: "edr-green",
},
]}
/>
<Card p={0} withBorder shadow="sm" radius="lg">
@@ -444,7 +415,6 @@ export default function ContractClearanceListPage({
rows={pagedRows}
loading={isLoading}
onOpen={openDetail}
isHistory={isHistory}
/>
)}
</Stack>
@@ -458,12 +428,10 @@ function ClearanceCardGrid({
rows,
loading,
onOpen,
isHistory = false,
}: {
rows: ClearanceRow[];
loading: boolean;
onOpen: (id: string) => void;
isHistory?: boolean;
}) {
if (loading) {
return (
@@ -480,7 +448,7 @@ function ClearanceCardGrid({
<ThemeIcon variant="light" color="gray" radius="xl" size={48}>
<Inbox size={22} />
</ThemeIcon>
<Text c="dimmed">No contracts awaiting review.</Text>
<Text c="dimmed">No contracts need customs clearance.</Text>
</Stack>
);
}
@@ -495,7 +463,7 @@ function ClearanceCardGrid({
}}
>
{rows.map((r) => (
<ClearanceCard key={r.id} row={r} onOpen={() => onOpen(r.id)} isHistory={isHistory} />
<ClearanceCard key={r.id} row={r} onOpen={() => onOpen(r.id)} />
))}
</Box>
);
@@ -504,11 +472,9 @@ function ClearanceCardGrid({
function ClearanceCard({
row,
onOpen,
isHistory = false,
}: {
row: ClearanceRow;
onOpen: () => void;
isHistory?: boolean;
}) {
return (
<Card
@@ -545,9 +511,7 @@ function ClearanceCard({
</Group>
</Box>
</Group>
<Badge size="sm" variant="light" color={isHistory ? "gray" : "edr-green"} radius="sm">
{isHistory ? "Cleared" : "Under review"}
</Badge>
<StatusBadge row={row} />
</Group>
<Box