Merge pull request #575 from Tria-plc/freight_feature/usermanagement

freight_feature/usermanagement
This commit is contained in:
marshal
2026-07-09 12:03:37 +03:00
committed by GitHub

View File

@@ -1,40 +1,100 @@
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import { Badge, Card, Group, Loader, Stack, Text } from "@mantine/core";
import { ChevronRight, PackageCheck, Ship } from "lucide-react";
import {
Badge,
Box,
Card,
Group,
Loader,
SegmentedControl,
Stack,
Text,
} from "@mantine/core";
import { ChevronRight, FileSignature, PackageCheck, Ship } from "lucide-react";
import { PageContainer } from "@/components/page/PageContainer";
import { PageHeader } from "@/components/page/PageHeader";
import { useDjClearanceQueue } from "@/hooks/contracts/useContracts";
import { useBookingDjClearanceQueue } from "@/hooks/bookings/useBookings";
type QueueTab = "contracts" | "shipments";
const prettyStatus = (s?: string | null) =>
(s ?? "")
.toLowerCase()
.replace(/_/g, " ")
.replace(/^\w/, (c) => c.toUpperCase());
/**
* GL Djibouti clearance queues:
* - Contracts: ONE_TIME customs contracts in phased clearance (legacy flow).
* - Shipments: GENERAL-contract bookings in per-booking clearance awaiting a DJ
* action (DO collection after ET finalizes pre-clearance, RO for exports,
* loading milestones). Managed like the one-time flow, but per booking.
*/
export default function GlDjiboutiClearanceListPage() {
const navigate = useNavigate();
const [tab, setTab] = useState<QueueTab>("shipments");
const { data: contractQueue, isLoading: contractsLoading } = useDjClearanceQueue();
const { data: bookingQueue, isLoading: bookingsLoading } =
useBookingDjClearanceQueue();
const contractItems = contractQueue?.items ?? [];
const bookingItems = bookingQueue ?? [];
const isLoading = tab === "contracts" ? contractsLoading : bookingsLoading;
return (
<PageContainer>
<PageHeader
title="GL Djibouti — Clearance"
subtitle="Customs contracts and shipment bookings handed off to Djibouti GL."
/>
{contractsLoading || bookingsLoading ? (
<Group justify="center" py={60}>
<Loader color="edr-green" />
</Group>
) : (
<Stack gap="sm">
{contractItems.length === 0 && bookingItems.length === 0 ? (
<Text c="dimmed" ta="center" py="xl">
No Djibouti customs work yet.
</Text>
) : (
<>
{contractItems.map((c) => (
<Stack gap="lg">
<PageHeader
title="GL Djibouti — Clearance"
subtitle="Customs contracts and shipment bookings handed off to Djibouti GL."
/>
<SegmentedControl
value={tab}
onChange={(v) => setTab(v as QueueTab)}
radius="md"
data={[
{
value: "shipments",
label: (
<Group gap={6} wrap="nowrap">
<PackageCheck size={15} />
<Box visibleFrom="sm">Shipments</Box>
<Badge size="sm" radius="sm" variant="light" color="edr-green">
{bookingItems.length}
</Badge>
</Group>
),
},
{
value: "contracts",
label: (
<Group gap={6} wrap="nowrap">
<FileSignature size={15} />
<Box visibleFrom="sm">Contracts</Box>
<Badge size="sm" radius="sm" variant="light" color="gray">
{contractItems.length}
</Badge>
</Group>
),
},
]}
/>
{isLoading ? (
<Group justify="center" py={60}>
<Loader color="edr-green" />
</Group>
) : tab === "contracts" ? (
<Stack gap="sm">
{contractItems.length === 0 ? (
<Text c="dimmed" ta="center" py="xl">
No Djibouti customs contracts yet.
</Text>
) : (
contractItems.map((c) => (
<Card
key={c.id}
withBorder
@@ -49,7 +109,7 @@ export default function GlDjiboutiClearanceListPage() {
<div>
<Text fw={700}>{c.reference}</Text>
<Text size="sm" c="dimmed">
{c.tradeDirection} · {c.status}
{c.tradeDirection} · {prettyStatus(c.status)}
</Text>
</div>
</Group>
@@ -61,15 +121,24 @@ export default function GlDjiboutiClearanceListPage() {
</Group>
</Group>
</Card>
))}
{bookingItems.map((b) => (
))
)}
</Stack>
) : (
<Stack gap="sm">
{bookingItems.length === 0 ? (
<Text c="dimmed" ta="center" py="xl">
No shipment bookings awaiting a Djibouti action.
</Text>
) : (
bookingItems.map((b) => (
<Card
key={b.id}
withBorder
radius="md"
padding="md"
style={{ cursor: "pointer" }}
onClick={() => navigate(`/dashboard/clearance/${b.id}`)}
onClick={() => navigate(`/dashboard/gl-djibouti/clearance/${b.id}`)}
>
<Group justify="space-between" wrap="nowrap">
<Group gap="sm">
@@ -80,7 +149,8 @@ export default function GlDjiboutiClearanceListPage() {
<div>
<Text fw={700}>{b.reference}</Text>
<Text size="sm" c="dimmed">
{b.tradeDirection} · {b.status}
{b.tradeDirection} · {prettyStatus(b.status)}
{b.company?.name ? ` · ${b.company.name}` : ""}
</Text>
</div>
</Group>
@@ -92,11 +162,11 @@ export default function GlDjiboutiClearanceListPage() {
</Group>
</Group>
</Card>
))}
</>
)}
</Stack>
)}
))
)}
</Stack>
)}
</Stack>
</PageContainer>
);
}