import React, { useState, useMemo, useRef, useEffect } from 'react'; import { Song } from '../types'; import { Play, MoreHorizontal, Heart, ThumbsDown, ListPlus, Pause, Search, Filter, Check, Globe, Lock, Loader2, ThumbsUp, Share2, Video, Info, Clock } from 'lucide-react'; import { useAuth } from '../context/AuthContext'; import { SongDropdownMenu } from './SongDropdownMenu'; import { ShareModal } from './ShareModal'; import { AlbumCover } from './AlbumCover'; interface SongListProps { songs: Song[]; currentSong: Song | null; selectedSong: Song | null; likedSongIds: Set; isPlaying: boolean; onPlay: (song: Song) => void; onSelect: (song: Song) => void; onToggleLike: (songId: string) => void; onAddToPlaylist: (song: Song) => void; onOpenVideo?: (song: Song) => void; onShowDetails?: (song: Song) => void; onNavigateToProfile?: (username: string) => void; onReusePrompt?: (song: Song) => void; onDelete?: (song: Song) => void; } // ... existing code ... // Define Filter Types type FilterType = 'liked' | 'public' | 'private' | 'generating'; const FILTERS: { id: FilterType; label: string; icon: React.ReactNode }[] = [ { id: 'liked', label: 'Liked', icon: }, { id: 'public', label: 'Public', icon: }, { id: 'private', label: 'Private', icon: }, { id: 'generating', label: 'Generating', icon: }, ]; export const SongList: React.FC = ({ songs, currentSong, selectedSong, likedSongIds, isPlaying, onPlay, onSelect, onToggleLike, onAddToPlaylist, onOpenVideo, onShowDetails, onNavigateToProfile, onReusePrompt, onDelete }) => { const { user } = useAuth(); const [searchQuery, setSearchQuery] = useState(''); const [activeFilters, setActiveFilters] = useState>(new Set()); const [isFilterOpen, setIsFilterOpen] = useState(false); const filterRef = useRef(null); // Close filter dropdown when clicking outside useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if (filterRef.current && !filterRef.current.contains(event.target as Node)) { setIsFilterOpen(false); } }; document.addEventListener('mousedown', handleClickOutside); return () => document.removeEventListener('mousedown', handleClickOutside); }, []); const toggleFilter = (filterId: FilterType) => { setActiveFilters(prev => { const newFilters = new Set(prev); if (newFilters.has(filterId)) { newFilters.delete(filterId); } else { newFilters.add(filterId); } return newFilters; }); }; const filteredSongs = useMemo(() => { return songs.filter(song => { // 1. Search Logic const matchesSearch = song.title.toLowerCase().includes(searchQuery.toLowerCase()) || song.style.toLowerCase().includes(searchQuery.toLowerCase()) || song.tags.some(tag => tag.toLowerCase().includes(searchQuery.toLowerCase())); if (!matchesSearch) return false; // 2. Filter Logic if (activeFilters.size === 0) return true; if (activeFilters.has('liked') && !likedSongIds.has(song.id)) return false; if (activeFilters.has('public') && !song.isPublic) return false; if (activeFilters.has('private') && song.isPublic) return false; if (activeFilters.has('generating') && !song.isGenerating) return false; return true; }); }, [songs, searchQuery, activeFilters, likedSongIds]); return (
{/* Container constraint */} {/* Header */}
Workspaces My Workspace
setSearchQuery(e.target.value)} placeholder="Search your songs..." className="w-full bg-zinc-100 dark:bg-[#121214] border border-zinc-200 dark:border-white/10 rounded-lg pl-10 pr-4 py-2.5 text-sm text-zinc-900 dark:text-white focus:outline-none focus:border-zinc-400 dark:focus:border-white/20 placeholder-zinc-500 dark:placeholder-zinc-600 transition-colors" />
{/* Filter Dropdown */} {isFilterOpen && (
Refine By
{FILTERS.map(filter => ( ))}
)}
{/* List */}
{/* Reduced vertical spacing */} {filteredSongs.length === 0 ? (

No songs match your filters.

) : ( filteredSongs.map((song) => ( onPlay(song)} onSelect={() => onSelect(song)} onToggleLike={() => onToggleLike(song.id)} onAddToPlaylist={() => onAddToPlaylist(song)} onOpenVideo={() => onOpenVideo && onOpenVideo(song)} onShowDetails={() => onShowDetails && onShowDetails(song)} onNavigateToProfile={onNavigateToProfile} onReusePrompt={() => onReusePrompt?.(song)} onDelete={() => onDelete?.(song)} /> )) )}
{/* End container */}
); }; interface SongItemProps { song: Song; isCurrent: boolean; isSelected: boolean; isLiked: boolean; isPlaying: boolean; isOwner: boolean; onPlay: () => void; onSelect: () => void; onToggleLike: () => void; onAddToPlaylist: () => void; onOpenVideo?: () => void; onShowDetails?: () => void; onNavigateToProfile?: (username: string) => void; onReusePrompt?: () => void; onDelete?: () => void; } const SongItem: React.FC = ({ song, isCurrent, isSelected, isLiked, isPlaying, isOwner, onPlay, onSelect, onToggleLike, onAddToPlaylist, onOpenVideo, onShowDetails, onNavigateToProfile, onReusePrompt, onDelete }) => { const [showDropdown, setShowDropdown] = useState(false); const [shareModalOpen, setShareModalOpen] = useState(false); const [imageError, setImageError] = useState(false); return ( <>
{/* Cover Art - Reduced size */}
{/* Use gradient fallback if no coverUrl or image fails to load */} {(!song.coverUrl || imageError) ? ( ) : ( {song.title} setImageError(true)} /> )} {song.isGenerating ? (
{song.queuePosition ? ( /* Queue indicator */ <>
Queue #{song.queuePosition} ) : ( /* Generating - Music Waveform Animation */
)}
) : (
{ e.stopPropagation(); onPlay(); }} >
{isCurrent && isPlaying ? ( ) : ( )}
)}
{/* Content */}

{song.title || (song.isGenerating ? (song.queuePosition ? "Queued..." : "Creating...") : "Untitled")}

v1.5 {song.isPublic === false && ( )}
{ e.stopPropagation(); if (song.creator && onNavigateToProfile) { onNavigateToProfile(song.creator); } }} >
{(song.creator?.[0] || 'U').toUpperCase()}
{song.creator || 'Unknown'}

{song.style}

{song.isGenerating && (
1 ? (song.progress ?? 0) / 100 : (song.progress ?? 0)) * 100) )}%`, }} />
)}
{/* Actions Row - Hidden while generating */} {!song.isGenerating && (
{/* Info Button - Visible only on small/medium screens where sidebar is hidden */}
setShowDropdown(false)} isOwner={isOwner} onCreateVideo={() => onOpenVideo?.(song)} onReusePrompt={() => onReusePrompt?.(song)} onAddToPlaylist={() => onAddToPlaylist?.(song)} onDelete={() => onDelete?.(song)} onShare={() => setShareModalOpen(true)} />
)}
{/* Timestamp */}
{song.isGenerating ? ( {song.queuePosition ? `#${song.queuePosition}` : 'Creating...'} ) : song.duration}
setShareModalOpen(false)} song={song} /> ); };