Skip to content

Add camera barcode/QR scanner to batch scan and book edit#440

Open
gunwald wants to merge 5 commits into
jzakotnik:mainfrom
gunwald:427-camera-barcode-scanner
Open

Add camera barcode/QR scanner to batch scan and book edit#440
gunwald wants to merge 5 commits into
jzakotnik:mainfrom
gunwald:427-camera-barcode-scanner

Conversation

@gunwald

@gunwald gunwald commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Closes #427

Summary

  • Adds a fullscreen camera scanner overlay (ZXing BrowserMultiFormatReader) reachable from a camera icon inside the ISBN input field
  • Available on the batch scan page and the single book edit / /book/new ISBN field
  • Supports EAN-13 / ISBN-10 / ISBN-13 barcodes and QR codes; back camera preferred automatically on mobile; camera-switch button when multiple cameras are present; permission-denied and no-camera error states with retry
  • On detection the overlay closes, the stream stops, and the ISBN feeds the existing lookup path (cover fetch, quantity increment, sounds)

Hardening (from review)

  • Stop the MediaStream when the scanner is closed/unmounted before decodeFromVideoDevice() resolves, so the camera light doesn't stay on
  • Replace the loose /^\d{10,13}$/ check with the canonical isIsbnLike() / normalizeIsbn() utils so only real ISBN-10/13 codes are accepted (11/12-digit non-ISBN barcodes are rejected)
  • Restore the "invalid ISBN" warning on manual batch input instead of silently clearing the field
  • Disable the camera button when the field is read-only

Test plan

  • Batch scan over HTTPS on a phone — scan an EAN-13 book barcode; an entry appears
  • /book/new — camera icon in the ISBN field fills the ISBN and autofill works
  • Manual junk input warns instead of silently clearing
  • Login still works (csrf change is on a separate branch)

gunwald and others added 5 commits June 27, 2026 01:21
Adds a camera icon inside the ISBN input field (right side, same
pattern as Google search). Tapping it opens a fullscreen camera
overlay with a scan guide frame and animated sweep line.

ZXing (@zxing/browser + @zxing/library) handles decoding. Only
EAN-13/ISBN-10/13 shaped values are passed through — other barcode
types are silently ignored. NotFoundException (fires on every frame
with no barcode) is suppressed.

On mobile the back camera is preferred automatically. If multiple
cameras are available a switch button appears in the header.
Permission denied and no-camera states show an error with a retry
button.

On detection the overlay closes, the camera stream stops, and the
ISBN is fed directly into processIsbn — the same path as manual
input, so cover fetching, quantity increment, and sound effects all
work identically.

Scan animation keyframe added to globals.css.
- Add camera icon button inside ISBN input on /book/new and book edit
  page (same ZXing overlay as batch scan; detection fills isbn field)
- Fix csrfToken undefined serialization on login page (getCsrfToken
  returns undefined in newer next-auth; coerce to null)
- Add dev:https npm script for phone testing over local network
  (mkcert cert, pins port 3002, inlines NEXTAUTH_URL override)
- Gitignore /certs/ directory for local mkcert files
- CameraScanner: fix race where decode callback fires before
  decodeFromVideoDevice resolves; use a session-local `detected` flag
  to prevent duplicate onDetected calls and stop the stream cleanly
- BookField: disable camera button when editable={false} so scans
  cannot overwrite a read-only form
- BookEditForm: remove book from handleCameraDetected useCallback deps
  via bookRef pattern to avoid stale closure clobbering concurrent edits
- login: remove dead csrfToken prop and getServerSideProps — the
  authorize function never reads hiddenFieldName, so the CSRF token
  fetch was unused and caused a serialization crash in newer next-auth
- BookField/i18n: replace hardcoded German aria-label with t() key
  (openCameraScanner added to de/en/es)
- CameraScanner: stop the MediaStream when the component is closed or
  unmounted before decodeFromVideoDevice() resolves. A cancelledRef is
  set in the unmount cleanup and checked after the await, so controls
  returned late are stopped instead of orphaned (camera light staying on)
- CameraScanner: replace loose /^\d{10,13}$/ check (accepted 11/12-digit
  non-ISBN barcodes) with the canonical isIsbnLike()/normalizeIsbn()
  utils, so only real ISBN-10/13 codes are accepted
- batchscan: restore the "invalid ISBN" warning for non-numeric manual
  input. handleScan now cleans non-digits before the empty check, so
  junk input warns and keeps the field instead of silently clearing it
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Barcodescanner via Kamera

1 participant