mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-03 03:53:39 +00:00
Merge pull request #575 from Tria-plc/freight_feature/usermanagement
freight_feature/usermanagement
This commit is contained in:
@@ -1,40 +1,100 @@
|
|||||||
|
import { useState } from "react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { Badge, Card, Group, Loader, Stack, Text } from "@mantine/core";
|
import {
|
||||||
import { ChevronRight, PackageCheck, Ship } from "lucide-react";
|
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 { PageContainer } from "@/components/page/PageContainer";
|
||||||
import { PageHeader } from "@/components/page/PageHeader";
|
import { PageHeader } from "@/components/page/PageHeader";
|
||||||
import { useDjClearanceQueue } from "@/hooks/contracts/useContracts";
|
import { useDjClearanceQueue } from "@/hooks/contracts/useContracts";
|
||||||
import { useBookingDjClearanceQueue } from "@/hooks/bookings/useBookings";
|
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() {
|
export default function GlDjiboutiClearanceListPage() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const [tab, setTab] = useState<QueueTab>("shipments");
|
||||||
const { data: contractQueue, isLoading: contractsLoading } = useDjClearanceQueue();
|
const { data: contractQueue, isLoading: contractsLoading } = useDjClearanceQueue();
|
||||||
const { data: bookingQueue, isLoading: bookingsLoading } =
|
const { data: bookingQueue, isLoading: bookingsLoading } =
|
||||||
useBookingDjClearanceQueue();
|
useBookingDjClearanceQueue();
|
||||||
|
|
||||||
const contractItems = contractQueue?.items ?? [];
|
const contractItems = contractQueue?.items ?? [];
|
||||||
const bookingItems = bookingQueue ?? [];
|
const bookingItems = bookingQueue ?? [];
|
||||||
|
const isLoading = tab === "contracts" ? contractsLoading : bookingsLoading;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContainer>
|
<PageContainer>
|
||||||
<PageHeader
|
<Stack gap="lg">
|
||||||
title="GL Djibouti — Clearance"
|
<PageHeader
|
||||||
subtitle="Customs contracts and shipment bookings handed off to Djibouti GL."
|
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" />
|
<SegmentedControl
|
||||||
</Group>
|
value={tab}
|
||||||
) : (
|
onChange={(v) => setTab(v as QueueTab)}
|
||||||
<Stack gap="sm">
|
radius="md"
|
||||||
{contractItems.length === 0 && bookingItems.length === 0 ? (
|
data={[
|
||||||
<Text c="dimmed" ta="center" py="xl">
|
{
|
||||||
No Djibouti customs work yet.
|
value: "shipments",
|
||||||
</Text>
|
label: (
|
||||||
) : (
|
<Group gap={6} wrap="nowrap">
|
||||||
<>
|
<PackageCheck size={15} />
|
||||||
{contractItems.map((c) => (
|
<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
|
<Card
|
||||||
key={c.id}
|
key={c.id}
|
||||||
withBorder
|
withBorder
|
||||||
@@ -49,7 +109,7 @@ export default function GlDjiboutiClearanceListPage() {
|
|||||||
<div>
|
<div>
|
||||||
<Text fw={700}>{c.reference}</Text>
|
<Text fw={700}>{c.reference}</Text>
|
||||||
<Text size="sm" c="dimmed">
|
<Text size="sm" c="dimmed">
|
||||||
{c.tradeDirection} · {c.status}
|
{c.tradeDirection} · {prettyStatus(c.status)}
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
</Group>
|
</Group>
|
||||||
@@ -61,15 +121,24 @@ export default function GlDjiboutiClearanceListPage() {
|
|||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
</Card>
|
</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
|
<Card
|
||||||
key={b.id}
|
key={b.id}
|
||||||
withBorder
|
withBorder
|
||||||
radius="md"
|
radius="md"
|
||||||
padding="md"
|
padding="md"
|
||||||
style={{ cursor: "pointer" }}
|
style={{ cursor: "pointer" }}
|
||||||
onClick={() => navigate(`/dashboard/clearance/${b.id}`)}
|
onClick={() => navigate(`/dashboard/gl-djibouti/clearance/${b.id}`)}
|
||||||
>
|
>
|
||||||
<Group justify="space-between" wrap="nowrap">
|
<Group justify="space-between" wrap="nowrap">
|
||||||
<Group gap="sm">
|
<Group gap="sm">
|
||||||
@@ -80,7 +149,8 @@ export default function GlDjiboutiClearanceListPage() {
|
|||||||
<div>
|
<div>
|
||||||
<Text fw={700}>{b.reference}</Text>
|
<Text fw={700}>{b.reference}</Text>
|
||||||
<Text size="sm" c="dimmed">
|
<Text size="sm" c="dimmed">
|
||||||
{b.tradeDirection} · {b.status}
|
{b.tradeDirection} · {prettyStatus(b.status)}
|
||||||
|
{b.company?.name ? ` · ${b.company.name}` : ""}
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
</Group>
|
</Group>
|
||||||
@@ -92,11 +162,11 @@ export default function GlDjiboutiClearanceListPage() {
|
|||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
</Card>
|
</Card>
|
||||||
))}
|
))
|
||||||
</>
|
)}
|
||||||
)}
|
</Stack>
|
||||||
</Stack>
|
)}
|
||||||
)}
|
</Stack>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user