import { Button } from "@/components/ui/button"; import { Checkbox } from "@/components/ui/checkbox"; import { Download, CheckCircle, XCircle, SkipForward, FileText, Globe } from "lucide-react"; import { Spinner } from "@/components/ui/spinner"; import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/ui/tooltip"; import { Pagination, PaginationContent, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, } from "@/components/ui/pagination"; import type { TrackMetadata, TrackAvailability } from "@/types/api"; import { TidalIcon, DeezerIcon, QobuzIcon, AmazonIcon } from "./PlatformIcons"; interface TrackListProps { tracks: TrackMetadata[]; searchQuery: string; sortBy: string; selectedTracks: string[]; downloadedTracks: Set; failedTracks: Set; skippedTracks: Set; downloadingTrack: string | null; isDownloading: boolean; currentPage: number; itemsPerPage: number; showCheckboxes?: boolean; hideAlbumColumn?: boolean; folderName?: string; isArtistDiscography?: boolean; // Lyrics props downloadedLyrics?: Set; failedLyrics?: Set; skippedLyrics?: Set; downloadingLyricsTrack?: string | null; // Availability props checkingAvailabilityTrack?: string | null; availabilityMap?: Map; onToggleTrack: (isrc: string) => void; onToggleSelectAll: (tracks: TrackMetadata[]) => void; onDownloadTrack: (isrc: string, name: string, artists: string, albumName: string, spotifyId?: string, folderName?: string, isArtistDiscography?: boolean) => void; onDownloadLyrics?: (spotifyId: string, name: string, artists: string, albumName: string, folderName?: string, isArtistDiscography?: boolean, position?: number) => void; onCheckAvailability?: (spotifyId: string, isrc?: string) => void; onPageChange: (page: number) => void; onAlbumClick?: (album: { id: string; name: string; external_urls: string }) => void; onArtistClick?: (artist: { id: string; name: string; external_urls: string }) => void; onTrackClick?: (track: TrackMetadata) => void; } export function TrackList({ tracks, searchQuery, sortBy, selectedTracks, downloadedTracks, failedTracks, skippedTracks, downloadingTrack, isDownloading, currentPage, itemsPerPage, showCheckboxes = false, hideAlbumColumn = false, folderName, isArtistDiscography = false, downloadedLyrics, failedLyrics, skippedLyrics, downloadingLyricsTrack, checkingAvailabilityTrack, availabilityMap, onToggleTrack, onToggleSelectAll, onDownloadTrack, onDownloadLyrics, onCheckAvailability, onPageChange, onAlbumClick, onArtistClick, onTrackClick, }: TrackListProps) { let filteredTracks = tracks.filter((track) => { if (!searchQuery) return true; const query = searchQuery.toLowerCase(); return ( track.name.toLowerCase().includes(query) || track.artists.toLowerCase().includes(query) || track.album_name.toLowerCase().includes(query) ); }); // Apply sorting if (sortBy === "title-asc") { filteredTracks = [...filteredTracks].sort((a, b) => a.name.localeCompare(b.name)); } else if (sortBy === "title-desc") { filteredTracks = [...filteredTracks].sort((a, b) => b.name.localeCompare(a.name)); } else if (sortBy === "artist-asc") { filteredTracks = [...filteredTracks].sort((a, b) => a.artists.localeCompare(b.artists)); } else if (sortBy === "artist-desc") { filteredTracks = [...filteredTracks].sort((a, b) => b.artists.localeCompare(a.artists)); } else if (sortBy === "duration-asc") { filteredTracks = [...filteredTracks].sort((a, b) => a.duration_ms - b.duration_ms); } else if (sortBy === "duration-desc") { filteredTracks = [...filteredTracks].sort((a, b) => b.duration_ms - a.duration_ms); } else if (sortBy === "downloaded") { filteredTracks = [...filteredTracks].sort((a, b) => { const aDownloaded = downloadedTracks.has(a.isrc); const bDownloaded = downloadedTracks.has(b.isrc); return (bDownloaded ? 1 : 0) - (aDownloaded ? 1 : 0); }); } else if (sortBy === "not-downloaded") { filteredTracks = [...filteredTracks].sort((a, b) => { const aDownloaded = downloadedTracks.has(a.isrc); const bDownloaded = downloadedTracks.has(b.isrc); return (aDownloaded ? 1 : 0) - (bDownloaded ? 1 : 0); }); } const totalPages = Math.ceil(filteredTracks.length / itemsPerPage); const startIndex = (currentPage - 1) * itemsPerPage; const endIndex = startIndex + itemsPerPage; const paginatedTracks = filteredTracks.slice(startIndex, endIndex); const tracksWithIsrc = filteredTracks.filter((track) => track.isrc); const allSelected = tracksWithIsrc.length > 0 && tracksWithIsrc.every((track) => selectedTracks.includes(track.isrc)); const formatDuration = (ms: number) => { const minutes = Math.floor(ms / 60000); const seconds = Math.floor((ms % 60000) / 1000); return `${minutes}:${seconds.toString().padStart(2, "0")}`; }; return (
{showCheckboxes && ( )} {!hideAlbumColumn && ( )} {paginatedTracks.map((track, index) => ( {showCheckboxes && ( )} {!hideAlbumColumn && ( )} ))}
onToggleSelectAll(filteredTracks)} /> # Title Album Duration Actions
{track.isrc && ( onToggleTrack(track.isrc)} /> )} {startIndex + index + 1}
{track.images && ( {track.name} )}
{onTrackClick ? ( onTrackClick(track)} > {track.name} ) : ( {track.name} )} {skippedTracks.has(track.isrc) ? ( ) : downloadedTracks.has(track.isrc) ? ( ) : failedTracks.has(track.isrc) ? ( ) : null}
{track.artists_data && track.artists_data.length > 0 ? ( track.artists_data.map((artist, i, arr) => ( {onArtistClick ? ( onArtistClick({ id: artist.id, name: artist.name, external_urls: artist.external_urls, }) } > {artist.name} ) : ( artist.name )} {i < arr.length - 1 && ", "} )) ) : onArtistClick && track.artist_id && track.artist_url ? ( onArtistClick({ id: track.artist_id!, name: track.artists, external_urls: track.artist_url!, }) } > {track.artists} ) : ( track.artists )}
{onAlbumClick && track.album_id && track.album_url ? ( onAlbumClick({ id: track.album_id!, name: track.album_name, external_urls: track.album_url!, }) } > {track.album_name} ) : ( track.album_name )} {formatDuration(track.duration_ms)}
{track.isrc && ( )} {track.spotify_id && onCheckAvailability && ( {availabilityMap?.has(track.spotify_id) ? (
) : (

Check Availability

)}
)} {track.spotify_id && onDownloadLyrics && (

Download Lyric

)}
{totalPages > 1 && ( { e.preventDefault(); if (currentPage > 1) onPageChange(currentPage - 1); }} className={ currentPage === 1 ? "pointer-events-none opacity-50" : "cursor-pointer" } /> {Array.from({ length: totalPages }, (_, i) => i + 1).map((page) => ( { e.preventDefault(); onPageChange(page); }} isActive={currentPage === page} className="cursor-pointer" > {page} ))} { e.preventDefault(); if (currentPage < totalPages) onPageChange(currentPage + 1); }} className={ currentPage === totalPages ? "pointer-events-none opacity-50" : "cursor-pointer" } /> )}
); }