fix(scanner): satisfy react-hooks/immutability and jsdom ResizeObserver in tests
- Move disambiguation-cancel tracker reset into useCameraScanner's new resetTrackedCard(cardId) (immutable map + setTrackedCards), wired via onTrackerReset — the identification hook no longer mutates state-derived objects, clearing the blocking react-hooks/immutability lint error. - Stub ResizeObserver in test/setup.js so ScannerCamera's workstation tests render under jsdom. - Drop unused eslint-disable directive in CollectionsPageView. npm run lint: 0 problems; vitest 231/231.
This commit is contained in:
parent
6fab22d315
commit
ca3b8a78c2
5 changed files with 24 additions and 5 deletions
|
|
@ -1,4 +1,3 @@
|
||||||
/* eslint-disable @next/next/no-img-element -- External or generated image URLs; next/image migration is out of scope. */
|
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import PermissionIndicator from './PermissionIndicator';
|
import PermissionIndicator from './PermissionIndicator';
|
||||||
import { VOCAB, collectionDisplayName } from '../lib/collection-vocabulary.js';
|
import { VOCAB, collectionDisplayName } from '../lib/collection-vocabulary.js';
|
||||||
|
|
|
||||||
|
|
@ -176,6 +176,16 @@ export function useCameraScanner({
|
||||||
setTrackedCards(next);
|
setTrackedCards(next);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const resetTrackedCard = useCallback((cardId) => {
|
||||||
|
const next = trackedCardsRef.current.map((card) => (
|
||||||
|
card.id === cardId
|
||||||
|
? { ...card, status: 'detecting', scanAttempts: 0, negativeAt: undefined }
|
||||||
|
: card
|
||||||
|
));
|
||||||
|
trackedCardsRef.current = next;
|
||||||
|
setTrackedCards(next);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const resetScanTrackers = useCallback(() => {
|
const resetScanTrackers = useCallback(() => {
|
||||||
trackedCardsRef.current = [];
|
trackedCardsRef.current = [];
|
||||||
setTrackedCards([]);
|
setTrackedCards([]);
|
||||||
|
|
@ -429,6 +439,7 @@ export function useCameraScanner({
|
||||||
startCamera,
|
startCamera,
|
||||||
stopCamera,
|
stopCamera,
|
||||||
removeTrackedCard,
|
removeTrackedCard,
|
||||||
|
resetTrackedCard,
|
||||||
resetScanTrackers,
|
resetScanTrackers,
|
||||||
triggerManualScan,
|
triggerManualScan,
|
||||||
streamRef,
|
streamRef,
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ export function useScannerIdentification({
|
||||||
onCardScanned,
|
onCardScanned,
|
||||||
onError,
|
onError,
|
||||||
onTrackerComplete,
|
onTrackerComplete,
|
||||||
|
onTrackerReset,
|
||||||
videoRef,
|
videoRef,
|
||||||
canvasRef,
|
canvasRef,
|
||||||
onVerifyCardRef,
|
onVerifyCardRef,
|
||||||
|
|
@ -118,10 +119,9 @@ export function useScannerIdentification({
|
||||||
};
|
};
|
||||||
|
|
||||||
const cancelDisambiguation = () => {
|
const cancelDisambiguation = () => {
|
||||||
if (disambiguation?.cardTracker) {
|
const { cardTracker } = disambiguation ?? {};
|
||||||
disambiguation.cardTracker.status = 'detecting';
|
if (cardTracker) {
|
||||||
disambiguation.cardTracker.scanAttempts = 0;
|
onTrackerReset?.(cardTracker.id);
|
||||||
disambiguation.cardTracker.negativeAt = undefined;
|
|
||||||
}
|
}
|
||||||
setDisambiguation(null);
|
setDisambiguation(null);
|
||||||
disambiguationRefineRef.current = null;
|
disambiguationRefineRef.current = null;
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,7 @@ export default function Scanner() {
|
||||||
onCardScanned: queue.handleCardScanned,
|
onCardScanned: queue.handleCardScanned,
|
||||||
onError: (msg) => console.error('Identification error:', msg),
|
onError: (msg) => console.error('Identification error:', msg),
|
||||||
onTrackerComplete: camera.removeTrackedCard,
|
onTrackerComplete: camera.removeTrackedCard,
|
||||||
|
onTrackerReset: camera.resetTrackedCard,
|
||||||
videoRef: camera.videoRef,
|
videoRef: camera.videoRef,
|
||||||
canvasRef: camera.canvasRef,
|
canvasRef: camera.canvasRef,
|
||||||
onVerifyCardRef,
|
onVerifyCardRef,
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,10 @@
|
||||||
process.env.JWT_SECRET = 'test-secret-for-vitest-only-do-not-use-in-prod';
|
process.env.JWT_SECRET = 'test-secret-for-vitest-only-do-not-use-in-prod';
|
||||||
process.env.NODE_ENV = 'test';
|
process.env.NODE_ENV = 'test';
|
||||||
|
|
||||||
|
if (!globalThis.ResizeObserver) {
|
||||||
|
globalThis.ResizeObserver = class ResizeObserver {
|
||||||
|
observe() {}
|
||||||
|
unobserve() {}
|
||||||
|
disconnect() {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue