WFDASH-WEBAPP/docs/superpowers/specs/2026-07-07-collection-confirm-selection-and-return-design.md
SJCoetz 9378685164 feat(collection-confirm): add full collection confirm workflow
Implement the complete collection confirm feature set:
- Add new `/collection-confirm` operational page for reviewing and confirming collected order items
- Add sidebar navigation entries for Collection Confirm and Invoicing
- Add `order_items` to the file proxy API whitelist for attachment access
- Install required testing dependencies and configure Vitest test setup
- Add full design documentation, test suite, and page overview screenshot
- Update package.json and build configuration files
2026-07-08 01:35:00 +02:00

5.5 KiB

Collection Confirm Selection And Return Design

Date: 2026-07-07 Area: src/app/(app)/collection-confirm/page.tsx, src/app/(app)/collection-confirm/view-model.ts Status: Drafted for review

Goal

Extend the /collection-confirm page so the PO Confirm this PO action only signs off the rows the operator has selected via per-row checkboxes, and add a per-row Return to pool action that sends a single item back to the collection pool with a reason note.

User Need

Operators can already confirm an entire PO at once with one shared invoice, but today the confirm applies to every row in the PO group automatically. Operators also need to send a single row back to the collection pool when a confirmation needs to wait for more information.

Approved Direction

  • Add a checkbox to every row. The page tracks the set of selected row ids.
  • The PO group header keeps the existing Confirm this PO action but now signs off only the selected rows in that group. The button label shows how many rows will be confirmed (e.g. Confirm 3 of 5).
  • Add a per-row Return to pool button that opens a small modal, requires a reason note, and flips the row back to collection_pool while appending a notes entry.

Scope

In scope:

  • per-row checkbox state and selection UI,
  • updating the PO group's Confirm this PO action to operate on the selected rows in the group,
  • adding the Return to pool modal and per-row button,
  • clearing the assignment lifecycle fields when a row is returned.

Out of scope:

  • changing the existing confirm modal or its audit note format,
  • adding a per-group Select all checkbox or any select-all-in-page affordance,
  • changing attachment or invoice upload behavior,
  • touching the collection-pool page.

Selection Behavior

  • Selection lives in a single Set<string> at the page level.
  • Each row carries an aria-label="Select item" checkbox on the left side of its card.
  • The checkbox state is controlled by the page-level selection state.
  • Selecting or deselecting a row never triggers a refetch.
  • Selection is cleared after a successful confirm or after Return to pool completes.

Confirm This PO Update

  • The PO header button label is computed from the group's selection count:
    • 0 selected: Confirm this PO, disabled with a small inline hint.
    • 1+ selected: Confirm <N> of <group size>, enabled.
  • The bulk confirm handler iterates over only the selected rows in that group.
  • Selection clears after the bulk confirm completes.
  • Problem-flagged rows without a confirming note are skipped from bulk confirm and surface a small inline message in the group.

Return to Pool

Modal

  • Title: Return to pool.
  • Fields:
    • Reason textarea, required.
  • The modal uses the existing ModalShell.Dialog pattern.

Behavior

  • On submit:
    • flip item_status to collection_pool,
    • clear drv_id, drv_status, assigned_at,
    • clear invoice_status to pending if present,
    • append a note entry to the unified notes feed with body Returned to pool. <reason>.
  • The row disappears from the collection-confirm list once the page reloads.
  • Failures keep the modal open with a toast error and leave the row in place.
  • The button is disabled while the row is busy.

Implementation Shape

  • src/app/(app)/collection-confirm/view-model.ts:
    • add buildReturnPatch({ row, actor, reason, ts }) that returns the patch and notes string,
    • export the new helper for tests.
  • src/app/(app)/collection-confirm/page.tsx:
    • add selectedRowIds: Set<string> state,
    • add a checkbox UI inside ConfirmCard,
    • update the PO group header to compute its action label from the selected subset,
    • update bulkConfirm to iterate over only the selected rows,
    • add a Return to pool button on each row,
    • add a ReturnToPoolDialog component,
    • wire the return handler to call the view-model helper.

Error Handling

  • Failed return writes keep the modal open with a toast error.
  • The selection set is never partially mutated by a failed write.
  • Empty selection on Confirm this PO is a no-op (the button is disabled).

Validation Plan

After implementation, validate that:

  1. Every row has a checkbox, and toggling it updates the page-level selection.
  2. Confirm this PO is disabled when nothing in the group is selected and shows the live Confirm N of M label otherwise.
  3. Confirm this PO signs off only the selected rows in the group, clearing the selection on success.
  4. Return to pool opens a modal that requires a reason and writes the row back to collection_pool with the reason in the notes feed.
  5. Returning a row clears the assignment lifecycle fields (drv_id, drv_status, assigned_at, invoice_status).
  6. Failed writes keep the modal open and surface toast errors.

Risks And Guardrails

Primary risk: accidentally confirming an unselected row when selection state is stale.

Guardrails:

  • bulkConfirm always re-derives the list of rows from the current selection before iterating,
  • selection is cleared after a successful confirm,
  • failed writes do not mutate the selection state.

Acceptance Criteria

This enhancement is complete when:

  • every row has a checkbox and selection lives in the page state,
  • Confirm this PO operates only on the selected rows in the group,
  • the PO header action label reflects the live selection count,
  • Return to pool flips a row back to collection_pool with a reason note,
  • returning a row clears the assignment lifecycle fields,
  • selection clears after a successful confirm or return,
  • no schema changes are introduced.