busy-office-ui
Menu

Pattern: RF pick

Who uses it: a picker with a gun in one hand and the other on the rack — the highest-volume RF activity in any warehouse. How often: hundreds of times a shift, one task line at a time. What "done" looks like: right bin confirmed by scan, right item confirmed by scan, quantity entered without taking gloves off, and the next line already on screen. The screen answers before the worker asks — task, bin, item, quantity — in the KV header every RF screen here shares. Not for checking stock without moving it — counting what a bin holds is the count pattern, which is blind by design; picking knows exactly what it wants and verifies the worker found it.

The screen — try it

Shown the way the scanner gets it: an isolated 360×640 document styled by ONLY the rf-essentials profile (Chrome/WebView 108) — not the docs bundle. One screen, not two: this page used to render the same component a second time at desktop width, which showed the reader a size no picker ever holds (roadmap 131.1).

Scan (type + Enter) A-01-04 or MAT-4471 — capture flashes green; anything else flashes red with the reason announced. There is no on-screen keypad, and that is the point (roadmap 135.4, owner): an RF gun ships a keyboard, so a grid of number buttons duplicates the platform and spends the screen's scarcest resource on it. inputmode="numeric" on the quantity input summons the device's own keypad and stays the zero-JS floor.

Markup

<!-- Header answers before the worker asks: which task, which bin,
     which item, how many. One scan field does bin AND item (the app knows
     which it expects next); the flash paints capture, YOUR validation
     paints the verdict. No on-screen keypad: inputmode summons the gun's
     own keyboard, and the screen keeps the room. -->
<dl class="bo-kv bo-kv--rows"> …Task / From bin / Item / Pick qty… </dl>

<input class="bo-input bo-input--code" data-scan-input data-scan-flash
    aria-describedby="scan-status" />
<p id="scan-status" data-scan-status aria-live="polite" class="bo-visually-hidden"></p>

<div class="bo-quantity"> …picked qty, spacious steppers… </div>

<div class="bo-btn-group bo-btn-group--bar">
  <button class="bo-btn bo-btn--secondary">Back</button>
  <button class="bo-btn bo-btn--secondary">Skip item</button>
  <button class="bo-btn bo-btn--secondary">Report short</button>
</div>

Anatomy

  1. Task header — KV rows: task id + position, source bin, item, required quantity. Everything a picker needs to trust the screen, nothing more.
  2. Scan field — one scan input for bin then item; the app knows which it expects next. Capture flashes ok; your validation calls flashScanResult('error', why).
  3. Quantity — quantity at spacious density — big enough for a gloved thumb, with inputmode="numeric" bringing up the device's keyboard for anything the steppers are too slow for.
  4. Exception bar — --bar: Back / Skip item / Report short. Intent-named, equal glove targets.

Data contract

RequestReturns / on failure
GET /rf/pick/nextthe next task line — this screen, server-rendered; an empty queue returns the task-menu redirect, never a blank pick screen
POST /rf/pick/:line/confirmbin + item + qty; 422 names WHICH check failed (wrong bin / wrong item / qty over need) so the worker fixes one thing, not everything
POST … short (qty < need)requires a reason code (select) — a silent short is tomorrow's stock discrepancy
409 on a re-assigned linere-render with who took it and the NEXT line — the worker keeps moving, never argues with a screen

States

StateWhat ships
Awaiting bin scanthe field names what it expects; the header carries the bin as text — the scan is confirmation, not discovery
Wrong bin / wrong itemerror flash + the reason in the live region; the field clears and refocuses for the retry
Short pickReport short opens the reason path; the line completes with its shortfall recorded, never silently adjusted
Line re-assigned (409)who took it, then the next line — flow beats blame
Queue emptyback to the task menu; an empty pick screen teaches nothing
Session lostthe RECONNECT state: on regaining the server, re-render the line as the server has it. Session persistence is infrastructure, not a screen promise
No JSthe form still posts on Enter (the wedge's terminator) and the server re-renders with the verdict — the flash is an enhancement; the KV header, field, quantity and bar are markup

Components used

complexity 2 of 4

↑↓ move Enter open Esc close