1
0
Fork 0
polaris-task-force/src/components/frontend/logistics/ShipmentsList.tsx
Z8MB1E cb2029ea97 feat(command-palette): register page-specific commands across UI
Wire CommandPalette/Provider into the frontend layout and add Cmd+K
hint in the SiteHeader. Register context-aware commands for banking,
helpdesk, mission RSVP, locker, shipments, and market pages.

Also removes the locker search's duplicate Cmd+K listener (now handled
globally), renames its button to 'Search Locker', and cleans up a
flappy page parenthetical.
2026-08-18 02:05:36 -04:00

113 lines
3.2 KiB
TypeScript

"use client";
import { useMemo, useState } from "react";
import type { Shipment } from "@/payload-types";
import { ShipmentCard } from "@/components/frontend/logistics/ShipmentCard";
import { Button } from "@/components/ui/button";
import { usePageCommands } from "@/components/command-palette/CommandPaletteContext";
import {
CheckCircleIcon,
ClockIcon,
ListFilterIcon,
TruckIcon,
XCircleIcon,
} from "lucide-react";
const statusFilters = [
{ label: "All", value: null },
{ label: "Active", value: "active" },
{ label: "Completed", value: "completed" },
{ label: "Cancelled", value: "cancelled" },
{ label: "Stranded", value: "stranded" },
];
const activeStatuses = ["dispatched", "in_transit", "pending"];
interface ShipmentsListProps {
shipments: Shipment[];
}
export function ShipmentsList({ shipments }: ShipmentsListProps) {
const [filter, setFilter] = useState<string | null>(null);
usePageCommands([
{
id: "shipments:filter-all",
group: "Shipments",
label: "Filter — All Shipments",
icon: ListFilterIcon,
keywords: ["filter", "all", "shipments"],
onSelect: () => setFilter(null),
},
{
id: "shipments:filter-active",
group: "Shipments",
label: "Filter — Active Shipments",
icon: ClockIcon,
keywords: ["filter", "active", "in transit", "pending"],
onSelect: () => setFilter("active"),
},
{
id: "shipments:filter-completed",
group: "Shipments",
label: "Filter — Completed Shipments",
icon: CheckCircleIcon,
keywords: ["filter", "completed", "arrived", "done"],
onSelect: () => setFilter("completed"),
},
{
id: "shipments:filter-cancelled",
group: "Shipments",
label: "Filter — Cancelled Shipments",
icon: XCircleIcon,
keywords: ["filter", "cancelled", "failed"],
onSelect: () => setFilter("cancelled"),
},
{
id: "shipments:filter-stranded",
group: "Shipments",
label: "Filter — Stranded Shipments",
icon: TruckIcon,
keywords: ["filter", "stranded", "stuck"],
onSelect: () => setFilter("stranded"),
},
]);
const filtered = useMemo(() => {
if (!filter) return shipments;
if (filter === "active") {
return shipments.filter((s) => activeStatuses.includes(s.status));
}
return shipments.filter((s) => s.status === filter);
}, [shipments, filter]);
return (
<div className="flex flex-col gap-4">
<div className="flex flex-wrap gap-1.5">
{statusFilters.map((f) => (
<Button
key={f.value ?? "all"}
variant={filter === f.value ? "default" : "outline"}
size="sm"
className="h-7 text-xs"
onClick={() => setFilter(f.value)}
>
{f.label}
</Button>
))}
</div>
{filtered.length === 0 ? (
<div className="flex flex-col items-center justify-center py-12 text-muted-foreground">
<p className="text-sm">No shipments found.</p>
</div>
) : (
<div className="flex flex-col gap-2">
{filtered.map((shipment) => (
<ShipmentCard key={shipment.id} shipment={shipment} />
))}
</div>
)}
</div>
);
}