/** * Component: Bulk Import - Match Review Step * Documentation: documentation/features/bulk-import.md * * Scrollable list of discovered audiobooks with Audible matches, * skip toggles, library status badges, and import controls. */ 'use client'; import React from 'react'; import { ArrowLeftIcon, CheckCircleIcon, ExclamationTriangleIcon, MusicalNoteIcon, XCircleIcon, } from '@heroicons/react/24/outline'; import { CheckCircleIcon as CheckCircleSolid } from '@heroicons/react/24/solid'; import { ScannedBook, formatBytes } from './types'; interface MatchReviewStepProps { books: ScannedBook[]; onToggleSkip: (index: number) => void; onStartImport: () => void; isImporting: boolean; importResults: any; onClose: () => void; onBack: () => void; } function BookRow({ book, onToggleSkip, }: { book: ScannedBook; onToggleSkip: () => void; }) { const isDisabled = book.inLibrary || book.hasActiveRequest; const isSkipped = book.skipped; const hasMatch = book.match !== null; // Low confidence when search term came from a filename or folder name fallback, // BUT not when an ASIN was extracted directly from the folder name (that's a // direct lookup and is as reliable as embedded metadata tags). const isLowConfidence = (book.metadataSource === 'file_name' || book.metadataSource === 'folder_name') && !book.extractedAsin; return (
{book.match!.title}
{isLowConfidence && ( Low Confidence )}{book.match!.author} {book.match!.narrator && ( {' '}· {book.match!.narrator} )}
> ) : ( <>{book.folderName}
No MatchCould not find this title on Audible
> )}{book.relativePath}
{succeeded} audiobook{succeeded !== 1 ? 's' : ''} queued for import.
{failed > 0 && ({failed} book{failed !== 1 ? 's' : ''} could not be queued.
)}Files will be organized, tagged, and imported into your library. Check the admin dashboard for progress.
> ) : ( <>{importResults.error || 'An unexpected error occurred'}
> )}The selected folder does not contain any folders with audio files. Try selecting a different folder.