New Transit Agents admin table (name, valid-from/to, active/suspended, validity badge) — DJ assign step now picks from it, active+valid only.

This commit is contained in:
Marshal
2026-07-29 05:38:35 +00:00
parent 891311d861
commit b17a72c280
59 changed files with 2903 additions and 451 deletions

View File

@@ -1,12 +1,15 @@
import type { ReactNode } from "react";
import { Badge, Stack, Tabs, Text } from "@mantine/core";
import { AlertTriangle, FileText, ShieldAlert } from "lucide-react";
import { AlertTriangle, FileText, Share2, ShieldAlert } from "lucide-react";
import type { Freight } from "@edr/types";
import { useAuth } from "@/auth/useAuth";
import { FREIGHT_PERMS, hasPermission } from "@/lib/permissions";
import { SectionCard } from "@/components/bookings/detail/SectionCard";
import { AssignRiskCard } from "@/components/contracts/gl-actions/AssignRiskCard";
import { IncidentReportCard } from "@/components/contracts/gl-actions/IncidentReportCard";
import { ClearanceUploadedDocumentsPanel } from "@/components/contracts/ClearanceUploadedDocumentsPanel";
import { GlExchangePanel } from "@/components/contracts/GlExchangePanel";
export interface ClearanceOpsTabsProps {
bookingId: string | undefined;
@@ -17,6 +20,12 @@ export interface ClearanceOpsTabsProps {
/** Phased customs workflow files — enables the Uploaded documents tab. */
workflowFiles?: Freight.ClearanceWorkflowFile[];
showWorkflowFilesTab?: boolean;
/**
* Booking or contract id whose GL Ethiopia ↔ GL Djibouti document exchange
* belongs on this page. Undefined hides the tab; it is also hidden from staff
* who hold neither desk's clearance-actions permission.
*/
exchangeEntityId?: string;
tradeDirection?: string;
onViewFile?: (file: { name: string; url: string }) => void;
onDownloadFile?: (file: { id: string; name: string }) => void;
@@ -40,6 +49,7 @@ export function ClearanceOpsTabs({
clearanceTab,
workflowFiles = [],
showWorkflowFilesTab = false,
exchangeEntityId,
tradeDirection = "IMPORT",
onViewFile,
onDownloadFile,
@@ -53,7 +63,12 @@ export function ClearanceOpsTabs({
return true;
}).length;
const showDocuments = showWorkflowFilesTab && Boolean(onViewFile);
const hasTabs = (showOpsTabs && hasOps) || showDocuments;
const { user } = useAuth();
const showExchange =
Boolean(exchangeEntityId) &&
(hasPermission(user, FREIGHT_PERMS.contracts.clearanceEtActions) ||
hasPermission(user, FREIGHT_PERMS.contracts.clearanceDjActions));
const hasTabs = (showOpsTabs && hasOps) || showDocuments || showExchange;
if (!hasTabs) {
return <>{clearanceTab}</>;
@@ -78,6 +93,11 @@ export function ClearanceOpsTabs({
Uploaded documents
</Tabs.Tab>
) : null}
{showExchange ? (
<Tabs.Tab value="exchange" leftSection={<Share2 size={14} />}>
Document exchange
</Tabs.Tab>
) : null}
{showOpsTabs && riskMs ? (
<Tabs.Tab value="risk" leftSection={<ShieldAlert size={14} />}>
Risk assignment
@@ -103,6 +123,12 @@ export function ClearanceOpsTabs({
</Tabs.Panel>
) : null}
{showExchange ? (
<Tabs.Panel value="exchange">
<GlExchangePanel entityId={exchangeEntityId!} />
</Tabs.Panel>
) : null}
{showOpsTabs && riskMs && bookingId ? (
<Tabs.Panel value="risk">
<SectionCard icon={ShieldAlert} title="Customs risk" accent="edr-green">