feat(collection-pool): gate assign UI on ready_for_collection

Both the per-row Assign Driver button and the bulk-assign button in each
supplier section header now disable when the target row(s) have not been
marked ready for collection. Tooltips explain the reason.

This enforces the rule that a stop must be ready before it can be
assigned to a driver — same gate for single-row and bulk flows.
This commit is contained in:
SJCoetz 2026-07-11 22:56:42 +02:00
parent c88a52cf2d
commit ed9503706d

View file

@ -177,7 +177,13 @@ export function PoolRow({
</div>
<div className="flex flex-col items-stretch gap-2 lg:min-w-[11rem]">
<Button size="sm" variant={isAssigned ? "outline" : "default"} onClick={() => onOpenAssign(row)} disabled={busy}>
<Button
size="sm"
variant={isAssigned ? "outline" : "default"}
onClick={() => onOpenAssign(row)}
disabled={busy || !row.ready_for_collection}
title={!row.ready_for_collection ? "Mark this stop as ready before assigning" : undefined}
>
{isAssigned ? "Reschedule" : "Assign Driver"}
</Button>
<Button
@ -243,6 +249,15 @@ export function SupplierGroup({
(r) => getAssignmentState(r, todayYmd) !== "unassigned",
);
// Compute which rows WOULD be assigned if the user clicked the bulk
// assign button. The same gating rule from PoolRow applies here: a
// row can only be assigned once it's marked ready.
const targetRows = allSelected || selectedCount === 0
? group.rows
: group.rows.filter((r) => selectedIds.has(r.id));
const unreadyTargetCount = targetRows.filter((r) => !r.ready_for_collection).length;
const allTargetsReady = unreadyTargetCount === 0;
const eyebrowText = (() => {
if (group.topPoNumbers.length === 0) return null;
const head = group.topPoNumbers.map((p) => `PO ${p}`).join(", ");
@ -257,6 +272,12 @@ export function SupplierGroup({
? `Assign ${selectedCount} selected`
: `Assign all ${rowIds.length}`;
const assignDisabledReason = allAssigned
? "Every stop at this supplier is already assigned"
: !allTargetsReady
? `${unreadyTargetCount} ${unreadyTargetCount === 1 ? "stop" : "stops"} not marked ready — mark ready before assigning`
: undefined;
const onAssignClick = () => {
const ids = allSelected || selectedCount === 0 ? rowIds : rowIds.filter((id) => selectedIds.has(id));
onOpenBulkAssign(group.supplierId, group.supplierName, ids);
@ -301,8 +322,8 @@ export function SupplierGroup({
<Button
size="sm"
onClick={onAssignClick}
disabled={busy || allAssigned}
title={allAssigned ? "Every stop at this supplier is already assigned" : undefined}
disabled={busy || allAssigned || !allTargetsReady}
title={assignDisabledReason}
>
<Truck className="mr-1.5 size-3.5" />
{assignLabel}