/* eslint-disable @next/next/no-img-element -- External card thumbnails; next/image migration is out of scope. */ import { useRef } from 'react'; import { VOCAB } from '../../lib/collection-vocabulary.js'; import Button from '../ui/Button.js'; import GlassSurface from '../ui/GlassSurface.js'; export const TAB_RECENT = 'recent'; export const TAB_QUEUE = 'queue'; export const TAB_DUPLICATES = 'duplicates'; const EMPTY_COPY = { [TAB_RECENT]: 'No scans yet this session.', [TAB_QUEUE]: 'Scan queue is empty — matches appear here before you add them.', [TAB_DUPLICATES]: 'No duplicates detected.', }; export function getDuplicateCards(scannedCards, ownershipMap) { const sessionRepeatIds = new Set(); const seen = new Map(); for (const card of scannedCards) { const key = `${card.name}::${card.set}`; if (seen.has(key)) sessionRepeatIds.add(card.id); else seen.set(key, card.id); if ((card.quantity || 1) > 1) sessionRepeatIds.add(card.id); } return scannedCards.filter( (card) => sessionRepeatIds.has(card.id) || (card.databaseId && ownershipMap[card.databaseId]) ); } function queueTabAriaLabel(count) { if (count === 0) return 'Scan Queue'; if (count === 1) return 'Scan Queue, 1 unprocessed card'; return `Scan Queue, ${count} unprocessed cards`; } function duplicatesTabAriaLabel(count) { if (count === 0) return 'Duplicates'; if (count === 1) return 'Duplicates, 1 duplicate card'; return `Duplicates, ${count} duplicate cards`; } function HistoryChip({ card, isFocused, onFocus }) { const isFailed = Boolean(card.identifyFailed); return ( ); } function BatchProgressBanner({ batchProgress }) { if (!batchProgress?.active) return null; const { current, total, onCancel } = batchProgress; const percent = total > 0 ? Math.round((current / total) * 100) : 0; return (
Scanning {current} of {total}…
); } export default function ScannerHistoryStrip({ scannedCards, ownershipMap, focusedCardId, onFocusCard, activeTab, onTabChange, batchProgress = null, onClearAll, onCommitSelectedToOwned, onOpenListPicker, isProcessing = false, }) { const chipScrollerRef = useRef(null); const unprocessedCards = scannedCards.filter((card) => !card.processed); const duplicateCards = getDuplicateCards(scannedCards, ownershipMap || {}); const recentCards = [...scannedCards].reverse(); const tabCards = { [TAB_RECENT]: recentCards, [TAB_QUEUE]: unprocessedCards, [TAB_DUPLICATES]: duplicateCards, }; const visibleCards = tabCards[activeTab] ?? []; const handleViewAllScans = () => { const scroller = chipScrollerRef.current; if (scroller) { scroller.scrollLeft = scroller.scrollWidth; } }; const tabs = [ { id: TAB_RECENT, label: 'Recent Scans', badge: null, ariaLabel: 'Recent Scans', }, { id: TAB_QUEUE, label: 'Scan Queue', badge: unprocessedCards.length, ariaLabel: queueTabAriaLabel(unprocessedCards.length), }, { id: TAB_DUPLICATES, label: 'Duplicates', badge: duplicateCards.length, ariaLabel: duplicatesTabAriaLabel(duplicateCards.length), }, ]; return (
{tabs.map((tab) => { const isSelected = activeTab === tab.id; return ( ); })}
{tabs.map((tab) => ( ))}
); }