Skip to content

fix(scanner): repair both scanner apps (null of 2 + camera not available) - #2905

Merged
jung-thomas merged 2 commits into
DEVfrom
worktree-fix-scanner-both-apps
Oct 24, 2026
Merged

jung-thomas merged 2 commits into
DEVfrom
worktree-fix-scanner-both-apps

Conversation

@jung-thomas

Copy link
Copy Markdown
Contributor

Problem

Both scanner surfaces broke; #2902 (badge-scanner v2) only touched the Vue island + backend, leaving two separate defects.

1. /scanner-ui/ (UI5) — "null of 2" + dead scan

Root cause verified live on DEV via Playwright: every contestant> binding in App.view.xml was relative (claimedCount) not absolute (/claimedCount). With no binding context on the contestant JSONModel they resolved to null, so prizeCount rendered null of 2 while the model held 0; identity/stats were blank and the visible expressions mis-evaluated (card showed at idle). Injecting the absolute path on the live control: null of 2 → 0 of 2 → 1 of 2.
Also removed a duplicate view instantiation: the manifest declared the App view as both rootView and routing target main (same id) → adding element with duplicate id container-scanner---App on router init. Single-screen app; dropped the router.

2. /scanner-vue/ — "Camera scanning not available"

Root cause: useBarcodeScanner gated isSupported on 'BarcodeDetector' in window, which is absent on iOS Safari and desktop Edge/Chrome in this deployment. Now gates on getUserMedia in a secure context and decodes frames with a jsQR fallback when the native detector is missing. Manual-paste retained for no-camera cases.

Tests

  • hugo-apps/src/scanner-vue/__tests__/camera-support.test.ts — 8 pass (new gating logic)
  • vite build emits scanner-vue island with jsQR bundled
  • UI5: no unit harness; root cause + fix proven via live control injection; e2e guard runs post-deploy

Verification still pending

Not yet confirmed on a deployed DEV build (UI5 view file + real-camera scan). Requires DEV deploy after merge, then re-check in browser.

…outer

Root cause (verified live via Playwright on DEV):
- All contestant> bindings were relative (claimedCount) not absolute
  (/claimedCount). With no binding context on the contestant JSONModel,
  they resolved to null -> prizeCount rendered 'null of 2' while the
  model held 0; identity/stats blank; visible-state expressions wrong.
  Injecting the absolute path on the live control: 'null of 2' -> '0 of 2'
  -> '1 of 2'.
- manifest declared the App view as BOTH rootView AND routing target
  'main' (same id) -> 'adding element with duplicate id container-scanner---App'
  throw on router init. App has a single screen; dropped the router and
  its Component.js getRouter().initialize() call.

Untouched by #2902 (badge-scanner v2 only covered the Vue island + backend).
Root cause (confirmed live on DEV): useBarcodeScanner gated isSupported on
'BarcodeDetector' in window. That API is Chromium/Android-only — absent on
iOS Safari AND desktop Edge/Chrome in this deployment — so every such browser
fell through to showManualInput ('Camera scanning not available') despite
having a working camera (getUserMedia present, secure context).

- isSupported now = getUserMedia available in a secure context
  (extracted to camera-support.ts, unit-tested).
- Scan loop uses native BarcodeDetector when present, else decodes
  getUserMedia frames with jsQR (new dep, ~15KB) over a canvas.
- Manual-paste path retained as the fallback for no-camera/insecure cases.

Tests: hugo-apps/src/scanner-vue/__tests__/camera-support.test.ts (8 pass).
Follow-up to #2902 (badge-scanner v2), which shipped the BarcodeDetector-only gate.
@jung-thomas
jung-thomas merged commit 312d23c into DEV Oct 24, 2026
4 of 5 checks passed
@jung-thomas
jung-thomas deleted the worktree-fix-scanner-both-apps branch October 24, 2026 08:22
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.

1 participant