mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
179 lines
6.3 KiB
TypeScript
179 lines
6.3 KiB
TypeScript
import type { ReactNode } from "react";
|
|
import { Badge, Stack, Tabs, Text } from "@mantine/core";
|
|
import { AlertTriangle, FileText, Receipt, 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 { ClearanceChargesTab } from "@/components/contracts/ClearanceChargesTab";
|
|
import { GlExchangePanel } from "@/components/contracts/GlExchangePanel";
|
|
|
|
export interface ClearanceOpsTabsProps {
|
|
bookingId: string | undefined;
|
|
milestones?: Freight.IClearanceMilestone[];
|
|
/** When false, only the clearance tab content is rendered (no tab bar). */
|
|
showOpsTabs?: boolean;
|
|
clearanceTab: ReactNode;
|
|
/** 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;
|
|
}
|
|
|
|
function findMilestone(
|
|
milestones: Freight.IClearanceMilestone[] | undefined,
|
|
code: string,
|
|
): Freight.IClearanceMilestone | undefined {
|
|
return milestones?.find((m) => m.milestoneCode === code);
|
|
}
|
|
|
|
/**
|
|
* Document Clearance detail layout: primary clearance workflow plus optional
|
|
* uploaded documents, post-booking risk assignment, and incident reporting tabs.
|
|
*/
|
|
export function ClearanceOpsTabs({
|
|
bookingId,
|
|
milestones,
|
|
showOpsTabs = true,
|
|
clearanceTab,
|
|
workflowFiles = [],
|
|
showWorkflowFilesTab = false,
|
|
exchangeEntityId,
|
|
tradeDirection = "IMPORT",
|
|
onViewFile,
|
|
onDownloadFile,
|
|
}: ClearanceOpsTabsProps) {
|
|
const riskMs = findMilestone(milestones, "RISK_ASSIGNED");
|
|
const hasOps = Boolean(bookingId);
|
|
const isExport = tradeDirection === "EXPORT";
|
|
const uploadedDocCount = workflowFiles.filter((f) => {
|
|
if (!f.file) return false;
|
|
if (isExport) return f.category !== "duty";
|
|
return true;
|
|
}).length;
|
|
const showDocuments = showWorkflowFilesTab && Boolean(onViewFile);
|
|
const { user } = useAuth();
|
|
const showExchange =
|
|
Boolean(exchangeEntityId) &&
|
|
(hasPermission(user, FREIGHT_PERMS.contracts.clearanceEtActions) ||
|
|
hasPermission(user, FREIGHT_PERMS.contracts.clearanceDjActions));
|
|
// Post-finalization customer billing. This layout is only rendered on the ET
|
|
// clearance pages — the DJ page (GlClearanceDetailPage) mounts its own tab.
|
|
const showCharges =
|
|
Boolean(bookingId) &&
|
|
Boolean(onViewFile) &&
|
|
hasPermission(user, FREIGHT_PERMS.contracts.clearanceEtActions);
|
|
// Risk assignment + incident reporting hit bookings:operations endpoints.
|
|
const canOps = hasPermission(user, FREIGHT_PERMS.bookings.operations);
|
|
const hasTabs = (showOpsTabs && hasOps) || showDocuments || showExchange;
|
|
|
|
if (!hasTabs) {
|
|
return <>{clearanceTab}</>;
|
|
}
|
|
|
|
return (
|
|
<Tabs defaultValue="clearance" keepMounted={false}>
|
|
<Tabs.List mb="md">
|
|
<Tabs.Tab value="clearance">Clearance</Tabs.Tab>
|
|
{showDocuments ? (
|
|
<Tabs.Tab
|
|
value="documents"
|
|
leftSection={<FileText size={14} />}
|
|
rightSection={
|
|
uploadedDocCount > 0 ? (
|
|
<Badge size="xs" variant="light" color="edr-green" circle>
|
|
{uploadedDocCount}
|
|
</Badge>
|
|
) : undefined
|
|
}
|
|
>
|
|
Uploaded documents
|
|
</Tabs.Tab>
|
|
) : null}
|
|
{showExchange ? (
|
|
<Tabs.Tab value="exchange" leftSection={<Share2 size={14} />}>
|
|
Document exchange
|
|
</Tabs.Tab>
|
|
) : null}
|
|
{showCharges ? (
|
|
<Tabs.Tab value="charges" leftSection={<Receipt size={14} />}>
|
|
Customer charges
|
|
</Tabs.Tab>
|
|
) : null}
|
|
{showOpsTabs && canOps && riskMs ? (
|
|
<Tabs.Tab value="risk" leftSection={<ShieldAlert size={14} />}>
|
|
Risk assignment
|
|
</Tabs.Tab>
|
|
) : null}
|
|
{showOpsTabs && canOps && bookingId ? (
|
|
<Tabs.Tab value="incidents" leftSection={<AlertTriangle size={14} />}>
|
|
Incidents
|
|
</Tabs.Tab>
|
|
) : null}
|
|
</Tabs.List>
|
|
|
|
<Tabs.Panel value="clearance">{clearanceTab}</Tabs.Panel>
|
|
|
|
{showDocuments ? (
|
|
<Tabs.Panel value="documents">
|
|
<ClearanceUploadedDocumentsPanel
|
|
files={workflowFiles}
|
|
tradeDirection={tradeDirection}
|
|
onView={onViewFile!}
|
|
onDownload={onDownloadFile}
|
|
/>
|
|
</Tabs.Panel>
|
|
) : null}
|
|
|
|
{showExchange ? (
|
|
<Tabs.Panel value="exchange">
|
|
<GlExchangePanel entityId={exchangeEntityId!} />
|
|
</Tabs.Panel>
|
|
) : null}
|
|
|
|
{showCharges ? (
|
|
<Tabs.Panel value="charges">
|
|
<ClearanceChargesTab
|
|
bookingId={bookingId!}
|
|
roleMode="ET"
|
|
onViewFile={onViewFile!}
|
|
/>
|
|
</Tabs.Panel>
|
|
) : null}
|
|
|
|
{showOpsTabs && canOps && riskMs && bookingId ? (
|
|
<Tabs.Panel value="risk">
|
|
<SectionCard icon={ShieldAlert} title="Customs risk" accent="edr-green">
|
|
<AssignRiskCard bookingId={bookingId} milestone={riskMs} />
|
|
</SectionCard>
|
|
</Tabs.Panel>
|
|
) : null}
|
|
|
|
{showOpsTabs && canOps && bookingId ? (
|
|
<Tabs.Panel value="incidents">
|
|
<SectionCard icon={AlertTriangle} title="Incident reports" accent="edr-green">
|
|
<Stack gap="sm">
|
|
<Text size="sm" c="dimmed">
|
|
Log container or seal issues discovered during clearance handling.
|
|
</Text>
|
|
<IncidentReportCard bookingId={bookingId} />
|
|
</Stack>
|
|
</SectionCard>
|
|
</Tabs.Panel>
|
|
) : null}
|
|
</Tabs>
|
|
);
|
|
}
|