import React from 'react'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; import { Check, Clock3, ListMusic, Pencil, Play, Sparkles, Trash2 } from 'lucide-react'; import type { SubsonicPlaylist } from '../../api/subsonicTypes'; import { usePlayerStore } from '../../store/playerStore'; import { displayPlaylistName, isSmartPlaylistName, type PendingSmartPlaylist, } from '../../utils/playlist/playlistsSmart'; import { formatHumanHoursMinutes } from '../../utils/format/formatHumanDuration'; import { PlaylistCardMainCover, PlaylistSmartCoverCell } from './PlaylistCoverImages'; interface Props { pl: SubsonicPlaylist; selectionMode: boolean; selectedIds: Set; selectedPlaylists: SubsonicPlaylist[]; toggleSelect: (id: string, opts?: { shiftKey?: boolean }) => void; isPlaylistDeletable: (pl: SubsonicPlaylist) => boolean; deleteConfirmId: string | null; setDeleteConfirmId: React.Dispatch>; handleOpenSmartEditor: (pl: SubsonicPlaylist) => Promise; handleDelete: (e: React.MouseEvent, pl: SubsonicPlaylist) => void; handlePlay: (e: React.MouseEvent, pl: SubsonicPlaylist) => void; playingId: string | null; smartCoverIdsByPlaylist: Record; pendingSmart: PendingSmartPlaylist[]; filteredSongCountByPlaylist: Record; filteredDurationByPlaylist: Record; } export default function PlaylistCard({ pl, selectionMode, selectedIds, selectedPlaylists, toggleSelect, isPlaylistDeletable, deleteConfirmId, setDeleteConfirmId, handleOpenSmartEditor, handleDelete, handlePlay, playingId, smartCoverIdsByPlaylist, pendingSmart, filteredSongCountByPlaylist, filteredDurationByPlaylist, }: Props) { const { t } = useTranslation(); const navigate = useNavigate(); const openContextMenu = usePlayerStore(s => s.openContextMenu); return (
{ if (selectionMode) { toggleSelect(pl.id, { shiftKey: e.shiftKey }); } else { navigate(`/playlists/${pl.id}`); } }} onContextMenu={(e) => { e.preventDefault(); if (selectionMode && selectedIds.size > 0) { openContextMenu(e.clientX, e.clientY, selectedPlaylists, 'multi-playlist'); } else { openContextMenu(e.clientX, e.clientY, pl, 'playlist'); } }} onMouseLeave={() => { if (deleteConfirmId === pl.id) setDeleteConfirmId(null); }} style={selectionMode && selectedIds.has(pl.id) ? { position: 'relative', outline: '2px solid var(--accent)', outlineOffset: '2px', borderRadius: 'var(--radius-md)' } : { position: 'relative' }} > {!selectionMode && (
{isPlaylistDeletable(pl) && ( )} {isPlaylistDeletable(pl) && ( )}
)} {selectionMode && (
{selectedIds.has(pl.id) && }
)} {/* Cover area — server collage or fallback icon */}
{isSmartPlaylistName(pl.name) && (smartCoverIdsByPlaylist[pl.id]?.length ?? 0) > 0 ? (
{Array.from({ length: 4 }, (_, i) => { const id = smartCoverIdsByPlaylist[pl.id][i % smartCoverIdsByPlaylist[pl.id].length]; return id ? ( ) : (
); })}
) : pl.coverArt ? ( ) : (
)} {pendingSmart.some(p => p.id === pl.id || p.name === pl.name) && (
)} {/* Play overlay — same pattern as AlbumCard */}
{isSmartPlaylistName(pl.name) && } {displayPlaylistName(pl.name)}
{t('playlists.songs', { n: filteredSongCountByPlaylist[pl.id] ?? pl.songCount })} {(filteredDurationByPlaylist[pl.id] ?? pl.duration) > 0 && ( <> · {formatHumanHoursMinutes(filteredDurationByPlaylist[pl.id] ?? pl.duration)} )}
); }