refactor(collection-map): drop status / readiness / search filters

This commit is contained in:
SJCoetz 2026-07-11 23:42:13 +02:00
parent a26e7c6312
commit d876455e41

View file

@ -35,7 +35,7 @@ import {
useMap,
useMapEvents,
} from "react-leaflet";
import { Calendar, ExternalLink, MapPin, RefreshCw, Search, Truck, User as UserIcon, Users, X, Layers } from "lucide-react";
import { Calendar, ExternalLink, MapPin, RefreshCw, Truck, User as UserIcon, Users, X, Layers } from "lucide-react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
@ -80,14 +80,6 @@ const DARK_TILE_ATTRIBUTION = '&copy; <a href="https://www.openstreetmap.org/cop
// the marker factory call reads naturally without dereferencing the import.
const UNASSIGNED_PIN_COLOR = STOP_STATUS_COLOR.unassigned;
/** Status filter options (matches the segmented control on the sidebar). */
type StatusFilter = "all" | "assigned" | "unassigned";
const STATUS_FILTERS: ReadonlyArray<{ value: StatusFilter; label: string }> = [
{ value: "all", label: "All" },
{ value: "assigned", label: "Assigned" },
{ value: "unassigned", label: "Unassigned" },
];
/* ============================================================================
* Types
* ========================================================================= */
@ -309,12 +301,6 @@ export default function CollectionMapPage() {
const [suppliersWithoutCoords, setSuppliersWithoutCoords] = useState<string[]>([]);
const [date, setDate] = useState(ymdToday());
const [statusFilter, setStatusFilter] = useState<StatusFilter>("all");
// Ready-filter — narrows the visible map stops to ready/unready/all.
// Default `all` to keep behaviour compatible with existing dashboard
// data (every existing pool row is `ready=true` post-migration).
const [readyFilter, setReadyFilter] = useState<"all" | "ready" | "unready">("all");
const [search, setSearch] = useState("");
// Traffic overlay toggle — default OFF to conserve the TomTom
// freemium 2,500-tile/day budget. Operators can flip it on for a
// single planning session; Leaflet caches tiles client-side so
@ -448,28 +434,7 @@ export default function CollectionMapPage() {
return m;
}, [allUsers]);
const filteredItems = useMemo(() => {
const query = search.trim().toLowerCase();
return items.filter((it) => {
if (statusFilter === "assigned" && it.item_status !== "assigned") return false;
if (statusFilter === "unassigned" && it.item_status !== "collection_pool") return false;
// Ready-filter sits after the status filter so "ready + assigned"
// and "unassigned + ready" remain combinable — same logic as the
// collection-pool page.
if (readyFilter !== "all") {
const want = readyFilter === "ready";
if (Boolean(it.ready_for_collection) !== want) return false;
}
if (enabledDriverIds.size > 0) {
if (!it.drv_id || !enabledDriverIds.has(it.drv_id)) return false;
}
if (query) {
const hay = `${it.description} ${it.po_number || ""} ${it.supplier_name} ${it.order_number || ""}`.toLowerCase();
if (!hay.includes(query)) return false;
}
return true;
});
}, [items, statusFilter, readyFilter, enabledDriverIds, search]);
const filteredItems = useMemo(() => items, [items]);
/* -- grouping by supplier ------------------------------------------------ */
const supplierStops = useMemo<SupplierStop[]>(() => {
@ -752,64 +717,9 @@ export default function CollectionMapPage() {
);
})}
</div>
{/* Status filter — labelled so it doesn't read as a second copy
of the Ready filter that also starts with "All". */}
<div className="flex items-center gap-1.5">
<span className="text-[10px] font-semibold uppercase tracking-wider text-muted-foreground">Status</span>
<div className="inline-flex h-9 overflow-hidden rounded-md border bg-background">
{STATUS_FILTERS.map((opt) => (
<button
key={opt.value}
type="button"
onClick={() => setStatusFilter(opt.value)}
className={cn(
"px-3 text-xs font-medium transition-colors",
statusFilter === opt.value
? "bg-primary text-primary-foreground"
: "text-muted-foreground hover:bg-muted"
)}
>
{opt.label}
</button>
))}
</div>
</div>
{/* Ready filter — supplier-confirmed gate. Sits next to the
status filter so operators can layer them ("assigned + not
yet ready" is the most useful debug combo). */}
<div className="flex items-center gap-1.5">
<span className="text-[10px] font-semibold uppercase tracking-wider text-muted-foreground">Readiness</span>
<div className="inline-flex h-9 overflow-hidden rounded-md border bg-background">
{(["all", "ready", "unready"] as const).map((opt) => (
<button
key={opt}
type="button"
aria-pressed={readyFilter === opt}
onClick={() => setReadyFilter(opt)}
className={cn(
"px-3 text-xs font-medium transition-colors",
readyFilter === opt
? "bg-primary text-primary-foreground"
: "text-muted-foreground hover:bg-muted"
)}
>
{opt === "all" ? "All" : opt === "ready" ? "Ready" : "Unready"}
</button>
))}
</div>
</div>
</div>
<div className="flex flex-wrap items-center gap-2">
<div className="relative w-full sm:w-64">
<Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
<Input
value={search}
onChange={(event) => setSearch(event.target.value)}
placeholder="Search PO, supplier, item..."
className="h-9 pl-9 text-sm"
/>
</div>
<Button variant="outline" size="sm" className="h-9" onClick={fetchRows} disabled={loading}>
<RefreshCw className={cn("mr-1.5 h-4 w-4", loading && "animate-spin")} />
Refresh