import React, { useState, useRef, useEffect, useCallback } from 'react' import { Link, useNavigate } from 'react-router-dom' import { ScanLine, Camera, Keyboard, CheckCircle2, XCircle, Eye, Pencil, ShoppingCart, RotateCcw, Zap } from 'lucide-react' import { useData } from '../context/DataContext' import StatusBadge from '../components/StatusBadge' import CategoryBadge from '../components/CategoryBadge' // ─── Bluetooth / text-input scanner mode ───────────────────────────────────── function BluetoothScanner({ onScan }) { const [value, setValue] = useState('') const inputRef = useRef(null) useEffect(() => { inputRef.current?.focus() }, []) function handleKeyDown(e) { if (e.key === 'Enter') { const trimmed = value.trim() if (trimmed) { onScan(trimmed); setValue('') } } } return (

Bluetooth Scanner Mode

Connect your Bluetooth barcode scanner, click the field, and scan any item label. The scanner will auto-submit when it sends Enter.

setValue(e.target.value)} onKeyDown={handleKeyDown} autoFocus autoComplete="off" spellCheck={false} />

Or type an asset tag (e.g. TR-A1B2C3) and press Enter

) } // ─── Camera scanner mode ────────────────────────────────────────────────────── function CameraScanner({ onScan }) { const videoRef = useRef(null) const canvasRef = useRef(null) const frameRef = useRef(null) const [status, setStatus] = useState('idle') // idle | starting | running | error const [errorMsg, setErrorMsg] = useState('') const [lastScan, setLastScan] = useState(null) async function startCamera() { setStatus('starting') try { const stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' } }) videoRef.current.srcObject = stream await videoRef.current.play() setStatus('running') scanLoop() } catch (err) { setStatus('error') setErrorMsg(err.message || 'Camera access denied') } } function stopCamera() { cancelAnimationFrame(frameRef.current) const stream = videoRef.current?.srcObject stream?.getTracks().forEach(t => t.stop()) if (videoRef.current) videoRef.current.srcObject = null setStatus('idle') } useEffect(() => () => stopCamera(), []) async function scanLoop() { if (!videoRef.current || !canvasRef.current) return const video = videoRef.current const canvas = canvasRef.current const ctx = canvas.getContext('2d') async function tick() { if (video.readyState === video.HAVE_ENOUGH_DATA) { canvas.width = video.videoWidth canvas.height = video.videoHeight ctx.drawImage(video, 0, 0) const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height) try { // Dynamic import jsQR const jsQR = (await import('jsqr')).default const code = jsQR(imgData.data, imgData.width, imgData.height) if (code && code.data !== lastScan) { setLastScan(code.data) onScan(code.data) } } catch (_) {} } frameRef.current = requestAnimationFrame(tick) } frameRef.current = requestAnimationFrame(tick) } return (

Camera Scanner Mode

Uses your device camera to scan QR codes from printed labels. Requires camera permission.

{status === 'idle' && (

Camera is not active.

)} {status === 'starting' && (

Starting camera…

)} {status === 'running' && (