feat: leads QR scanner — Auto/Multi modes, 4-mode fancy selector, UX polish

Scanner modes (now 4, persisted per exhibit):
- Rapid:   confirm tap → auto-reset (existing, fixed)
- Qualify: confirm tap → navigate to lead detail (existing, fixed)
- Auto:    badge found → auto-add immediately, no confirmation tap needed
- Multi:   BarcodeDetector batch scan → responsive grid of confirm cards

Multi scanner (new ae_comp__lead_qr_scanner_multi.svelte):
- Native BarcodeDetector API (Chrome/Edge/Safari 17+); Firefox fallback message
- 16:9 viewfinder with corner guides + "Align up to 4 badges flat" overlay
- Capture Batch tap → up to 8 QR codes detected in one frame
- Per-card states: loading skeleton, ready (Add/Skip), blocked (opt-out),
  already-captured (View/OK), adding spinner, success (auto-fade), error
- Add All (N) bulk action; cards fade+scale out smoothly on dismiss

Mode selector (ae_tab__add.svelte):
- Replaces Rapid/Qualify toggle with collapsible 4-mode fancy select
- Trigger shows active mode icon (color-coded) + name + description
- 2×2 options grid expands on tap, closes on selection

QR scanner element (element_qr_scanner_v3.svelte):
- object-fit: cover eliminates 4:3 camera letterbox dead zone
- 7-second start timeout with actionable error message
- Starting/error overlays with high-contrast styling
- Try Again button with RefreshCw icon

Style guide updated: icon+text button rule (§8), btn/preset-filled workaround (§12)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Scott Idem
2026-03-20 16:30:38 -04:00
parent 14c2635df4
commit 334c3a21bc
6 changed files with 727 additions and 106 deletions

View File

@@ -34,6 +34,14 @@ export interface LeadsLocState {
edit_license_li: boolean;
// Key = exhibit ID (random), value = last-used tab name.
tab: Record<string, string>;
// Per-exhibit Add tab input mode: 'qr' | 'search'. Persisted so operator preference survives navigation.
tab_add_mode: Record<string, string>;
// Per-exhibit scan qualify mode:
// 'rapid' — confirm tap → auto-reset → scan next
// 'qualify' — confirm tap → navigate to lead detail
// 'auto' — no confirm, auto-add immediately → auto-reset
// 'multi' — BarcodeDetector batch scan, grid of confirm cards
tab_scan_qualify: Record<string, 'rapid' | 'qualify' | 'auto' | 'multi'>;
}
export interface TmpLicense {
@@ -110,7 +118,9 @@ export const leads_loc_defaults: LeadsLocState = {
// Per-exhibit current tab. Key = exhibit ID (random), value = tab name.
// Intentionally persisted so each exhibit's last-used tab is remembered across sessions.
// Example: {'LNDF-67-89-92': 'start', 'OFLN-32-38-14': 'add_scan'}
tab: {}
tab: {},
tab_add_mode: {},
tab_scan_qualify: {}
};
// In-memory leads state — resets on page load.