feat(booth): open the pay/exit modal on a hardware scan regardless of focus
A barcode/QR scanner is an HID "keyboard wedge" — it types the id + Enter into whatever holds focus. Previously that only worked while the ticket <input> was focused; a scan with focus elsewhere (or nowhere) went nowhere. New useScanner hook (apps/web/src/lib/use-scanner.ts): a document-level keydown listener that detects the scanner's FAST keystroke burst ended by Enter and opens the pay/exit modal via setActiveTicket — regardless of focus. A gap > 50ms resets the buffer, so human-paced typing with nothing focused never registers as a scan (min length 3 guards stray Enters). Keystrokes into an input/textarea/select/ contenteditable are ignored, so the manual ticket field still works by hand. The hook is paused while a modal is already open — a scan must not abandon an in-progress payment; the operator finishes/closes, then scans the next car. Verified at runtime (Playwright): a fast burst with focus on BODY opens the modal; a second scan while the modal is open is ignored; slow (120ms) human typing does NOT open it; the manual input submit still opens it. build+lint 14/14. Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
+10
@@ -1299,3 +1299,13 @@ viewport like /booth: a fixed title+filters, then a two-pane area (shift list |
|
||||
pane scrolls independently (min-h-0/flex-1 + overflow-y-auto) instead of the whole page growing.
|
||||
Verified at runtime (Playwright): /shift redirects, rows open the detail modal, layout fills height,
|
||||
booth still works (0 console errors). build+lint 14/14.
|
||||
|
||||
## [2026-06-21] feat | Booth: focus-independent hardware-scan capture
|
||||
A scan now opens the /booth pay/exit modal no matter what's focused (or if nothing is) — the operator
|
||||
needn't click the ticket field first. New useScanner hook (apps/web/src/lib/use-scanner.ts): a
|
||||
document-level keydown listener that detects the HID scanner's fast keystroke burst ended by Enter (gap
|
||||
> 50ms resets the buffer, so human-paced typing never triggers it; min length 3) and fires
|
||||
setActiveTicket. Ignores keystrokes into editable fields so the manual ticket input is unaffected;
|
||||
paused while a modal is open so a scan can't abandon an in-progress payment. Verified at runtime
|
||||
(Playwright): scan with focus on BODY opens the modal; second scan while open is ignored; slow typing
|
||||
doesn't trigger; manual form submit still works. build+lint 14/14. See [[booth-console]].
|
||||
|
||||
Reference in New Issue
Block a user