import React, { useState, useEffect } from 'react'; import { Song } from '../types'; import { Heart, Share2, Play, Pause, MoreHorizontal, X, Copy, Wand2, MoreVertical, Download, Repeat, Video, Music, Link as LinkIcon, Sparkles, Globe, Lock, Trash2, Edit3, Layers } from 'lucide-react'; import { songsApi } from '../services/api'; import { useAuth } from '../context/AuthContext'; import { SongDropdownMenu } from './SongDropdownMenu'; import { ShareModal } from './ShareModal'; import { AlbumCover } from './AlbumCover'; interface RightSidebarProps { song: Song | null; onClose?: () => void; onOpenVideo?: () => void; onReuse?: (song: Song) => void; onSongUpdate?: (song: Song) => void; onNavigateToProfile?: (username: string) => void; onNavigateToSong?: (songId: string) => void; isLiked?: boolean; onToggleLike?: (song: Song) => void; onDelete?: (song: Song) => void; onAddToPlaylist?: (song: Song) => void; onPlay?: (song: Song) => void; isPlaying?: boolean; currentSong?: Song | null; } export const RightSidebar: React.FC = ({ song, onClose, onOpenVideo, onReuse, onSongUpdate, onNavigateToProfile, onNavigateToSong, isLiked, onToggleLike, onDelete, onAddToPlaylist, onPlay, isPlaying, currentSong }) => { const { token, user } = useAuth(); const [showMenu, setShowMenu] = useState(false); const [isOwner, setIsOwner] = useState(false); const [tagsExpanded, setTagsExpanded] = useState(false); const [shareModalOpen, setShareModalOpen] = useState(false); const [copiedStyle, setCopiedStyle] = useState(false); const [copiedLyrics, setCopiedLyrics] = useState(false); const [isEditingTitle, setIsEditingTitle] = useState(false); const [titleDraft, setTitleDraft] = useState(''); const [titleError, setTitleError] = useState(null); const [isSavingTitle, setIsSavingTitle] = useState(false); useEffect(() => { if (song) { setIsOwner(user?.id === song.userId); } }, [song, user]); useEffect(() => { if (song) { setTitleDraft(song.title || ''); setIsEditingTitle(false); setTitleError(null); setIsSavingTitle(false); } }, [song?.id]); const startTitleEdit = () => { if (!song || !isOwner) return; setTitleDraft(song.title || ''); setTitleError(null); setIsEditingTitle(true); }; const cancelTitleEdit = () => { if (!song) return; setTitleDraft(song.title || ''); setTitleError(null); setIsEditingTitle(false); }; const saveTitleEdit = async () => { if (!song) return; if (!token) { setTitleError('Please sign in to rename.'); return; } const trimmed = titleDraft.trim(); if (!trimmed) { setTitleError('Title cannot be empty.'); return; } if (trimmed === song.title) { setIsEditingTitle(false); return; } setIsSavingTitle(true); setTitleError(null); try { await songsApi.updateSong(song.id, { title: trimmed }, token); onSongUpdate?.({ ...song, title: trimmed }); setIsEditingTitle(false); } catch (err) { const message = err instanceof Error ? err.message : 'Rename failed'; setTitleError(message); } finally { setIsSavingTitle(false); } }; const getSourceLabel = (url?: string) => { if (!url) return 'None'; try { const parsed = new URL(url, window.location.origin); const name = decodeURIComponent(parsed.pathname.split('/').pop() || url); return name.replace(/\.[^/.]+$/, '') || name; } catch { const parts = url.split('/'); const name = decodeURIComponent(parts[parts.length - 1] || url); return name.replace(/\.[^/.]+$/, '') || name; } }; const openSource = (url?: string) => { if (!url) return; const resolved = url.startsWith('http') ? url : `${window.location.origin}${url}`; window.open(resolved, '_blank'); }; if (!song) return (

Select a song to view details

); return (
{/* Header */}
Song Details
{/* Cover Art */}
onPlay?.(song)} > {song.coverUrl ? ( {song.title} { e.currentTarget.style.display = 'none'; }} /> ) : null} {!song.coverUrl && } {/* Overlay Gradient */}
{/* Play Button Overlay */}
{song.viewCount || 0}
{song.duration}
{/* Title & Artist Block */}
{!isEditingTitle ? (

onNavigateToSong?.(song.id)} className="text-2xl font-bold text-zinc-900 dark:text-white leading-tight tracking-tight cursor-pointer hover:underline" > {song.title}

) : (
setTitleDraft(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); void saveTitleEdit(); } if (e.key === 'Escape') { e.preventDefault(); cancelTitleEdit(); } }} className="w-full text-xl font-bold text-zinc-900 dark:text-white bg-white dark:bg-black/30 border border-zinc-200 dark:border-white/10 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-pink-500/40" maxLength={120} autoFocus />
{titleError && ( {titleError} )}
)}
{isOwner && !isEditingTitle && ( )} setShowMenu(false)} isOwner={isOwner} onCreateVideo={onOpenVideo} onReusePrompt={() => onReuse?.(song)} onDelete={() => onDelete?.(song)} onAddToPlaylist={() => onAddToPlaylist?.(song)} onShare={() => setShareModalOpen(true)} />
{song.creator ? song.creator[0].toUpperCase() : 'A'}
song.creator && onNavigateToProfile?.(song.creator)} className="text-sm font-semibold text-zinc-900 dark:text-white hover:underline cursor-pointer" > {song.creator || 'Anonymous'} Created {new Date(song.createdAt).toLocaleDateString()}
{/* Main Actions */}
{/* Icon Actions Row */}
} label={String(song.likeCount || 0)} active={isLiked} onClick={() => onToggleLike?.(song)} /> } onClick={() => setShareModalOpen(true)} />
{(song.generationParams?.referenceAudioUrl || song.generationParams?.sourceAudioUrl) && (
Sources
{song.generationParams?.referenceAudioUrl && (
Reference
{song.generationParams?.referenceAudioTitle || getSourceLabel(song.generationParams?.referenceAudioUrl)}
)} {song.generationParams?.sourceAudioUrl && (
Cover
{song.generationParams?.sourceAudioTitle || getSourceLabel(song.generationParams?.sourceAudioUrl)}
)}
)}
{/* Tags / Style */}

Style & Tags

setTagsExpanded(!tagsExpanded)} className={`flex flex-wrap gap-1.5 cursor-pointer relative ${!tagsExpanded ? 'max-h-[22px] overflow-hidden' : ''}`} > {Array.isArray(song.tags) && song.tags.length > 0 ? ( song.tags.map(tag => ( {tag} )) ) : ( song.style.split(',').map((tag, idx) => ( {tag.trim()} )) )} {!tagsExpanded && ( +more )}
{/* Lyrics Section */}

Lyrics

{song.lyrics ||
Instrumental
No lyrics generated
}
{song && ( setShareModalOpen(false)} song={song} /> )}
); }; const ActionButton: React.FC<{ icon: React.ReactNode; label?: string; active?: boolean; onClick?: () => void }> = ({ icon, label, active, onClick }) => ( );