mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
freight_feature/usermanagement
This commit is contained in:
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user