Compare commits

...

4 commits

Author SHA1 Message Date
Randall Stillwell
697dc3f5ef fix(scanner): resolve stale closure in handleCardScanned
Some checks are pending
CI / Lint (push) Waiting to run
CI / Schema map up to date (push) Waiting to run
CI / Forbidden patterns (9 checks) (push) Waiting to run
CI / Migrations apply (node-pg-migrate) (push) Waiting to run
CI / Unit tests (vitest) (push) Waiting to run
- Add scannedCardsRef to track latest queue state
- Use functional updater in setScannedCards to avoid stale mergeScannedCardEntry input
- Return cardEntry.id synchronously from handleCardScanned so onScanImageUploaded fires

This fixes the scanner queue stopping after 1 card (required page refresh to see more).
2026-09-11 17:40:16 -05:00
Randall Stillwell
3dc9b5852f fix(scanner): resolve stale closure in handleCardScanned
- Add scannedCardsRef to track latest queue state
- Use functional updater in setScannedCards to avoid stale mergeScannedCardEntry input
- Return cardEntry.id synchronously from handleCardScanned so onScanImageUploaded fires

This fixes the scanner queue stopping after 1 card (required page refresh to see more).
2026-09-11 13:07:30 -05:00
Randall Stillwell
4c1d22b935 fix(my-cards): collection display — summary + cards.map + empty-state + debug guard; branch fix/my-cards-collection-display 2026-09-09 17:51:48 -05:00
Randall Stillwell
e733dc5a13 Wire scanner feedback toasts and restore rescan uploads.
Some checks failed
CI / Lint (pull_request) Has been cancelled
CI / Schema map up to date (pull_request) Has been cancelled
CI / Forbidden patterns (9 checks) (pull_request) Has been cancelled
CI / Migrations apply (node-pg-migrate) (pull_request) Has been cancelled
Visual diff / Should run? (pull_request) Has been cancelled
CI / Unit tests (vitest) (pull_request) Has been cancelled
Convoy metrics gate / Require role-event telemetry on convoy PRs (pull_request) Has been cancelled
PR Health rollup / Aggregate gate status (pull_request) Has been cancelled
Preview smoke / Should run? (pull_request) Has been cancelled
Visual diff / Screenshot diff (pull_request) Has been cancelled
Preview smoke / Playwright smoke (pull_request) Has been cancelled
Show scan notices and camera/identify errors in the page toast, patch scanImageUrl after background upload completes, and fix debug upload logging.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-08 19:06:07 -05:00
2 changed files with 24 additions and 11 deletions

View file

@ -45,6 +45,11 @@ export function useScannerQueue({ user, sessionDestination, scanDefaults, deckMo
const addingInFlightRef = useRef(new Set()); const addingInFlightRef = useRef(new Set());
const [addingCardIds, setAddingCardIds] = useState(() => new Set()); const [addingCardIds, setAddingCardIds] = useState(() => new Set());
const cartPersistTimerRef = useRef(null); const cartPersistTimerRef = useRef(null);
const scannedCardsRef = useRef(scannedCards);
useEffect(() => {
scannedCardsRef.current = scannedCards;
}, [scannedCards]);
const persistCart = (cards, selection) => { const persistCart = (cards, selection) => {
saveScannerCart({ saveScannerCart({
@ -162,22 +167,25 @@ export function useScannerQueue({ user, sessionDestination, scanDefaults, deckMo
setUndoStack((prev) => prev.filter((u) => u.cardId !== cardId)); setUndoStack((prev) => prev.filter((u) => u.cardId !== cardId));
}, []); }, []);
const handleCardScanned = (cardData) => { const handleCardScanned = useCallback((cardData) => {
setAutoRouteError(null); setAutoRouteError(null);
const { cardEntry, scannedCards: nextQueue } = mergeScannedCardEntry( const { cardEntry, scannedCards: nextQueue } = mergeScannedCardEntry(
scannedCards, scannedCardsRef.current,
cardData, cardData,
scanDefaults scanDefaults
); );
setScannedCards(nextQueue); setScannedCards((prev) => {
setSelectedCards((prev) => { const { cardEntry: ce, scannedCards: nq } = mergeScannedCardEntry(prev, cardData, scanDefaults);
const next = new Set([...prev, cardEntry.id]); setSelectedCards((ps) => {
persistCart(nextQueue, next); const n = new Set([...ps, ce.id]);
return next; persistCart(nq, n);
return n;
});
return nq;
}); });
return cardEntry.id; return cardEntry.id;
}; }, [scanDefaults]);
const incrementCardQuantity = (cardId) => { const incrementCardQuantity = (cardId) => {
setScannedCards((prev) => setScannedCards((prev) =>

View file

@ -442,6 +442,11 @@ export default function MyCards() {
: 'space-y-4' : 'space-y-4'
} }
`}> `}>
{cards.length === 0 && !loading && (
<div className="col-span-full text-center py-12" style={{ color: 'var(--text-secondary)' }}>
<p>No cards loaded from /api/cards/owned (summary shows {collectionSummary?.totalCards ?? 'N/A'} via /api/user/stats).</p>
</div>
)}
{cards.map((card) => ( {cards.map((card) => (
<CardItem <CardItem
key={card.id} key={card.id}
@ -484,7 +489,7 @@ export default function MyCards() {
{/* No Cards Found */} {/* No Cards Found */}
{cards.length === 0 && !loading && ( {cards.length === 0 && !loading && (
<div className="text-center py-20"> <div className="text-center py-20" data-testid="my-cards-empty-state">
<div className="glass-panel w-16 h-16 mx-auto mb-4 rounded-2xl flex items-center justify-center"> <div className="glass-panel w-16 h-16 mx-auto mb-4 rounded-2xl flex items-center justify-center">
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24" style={{ color: 'var(--text-secondary)' }}> <svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24" style={{ color: 'var(--text-secondary)' }}>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" /> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" />