'use client' import { useState, useRef, useCallback, useEffect } from 'react' import { useMusicPlayer } from './music-provider' import { X, GripVertical, ArrowLeft, Search, Music } from 'lucide-react' import { useRouter } from 'next/navigation' interface QueueViewProps { open: boolean onClose: () => void } export function QueueView({ open, onClose }: QueueViewProps) { const { state, removeFromQueue, moveInQueue, jumpTo, clearQueue } = useMusicPlayer() const router = useRouter() // Drag state const [dragIndex, setDragIndex] = useState(null) const [overIndex, setOverIndex] = useState(null) const dragStartY = useRef(0) const dragNodeRef = useRef(null) const listRef = useRef(null) const upcomingStart = state.queueIndex + 1 const upcoming = state.queue.slice(upcomingStart) // Map upcoming array index to absolute queue index const toAbsolute = (i: number) => upcomingStart + i const handleDragStart = useCallback((e: React.MouseEvent | React.TouchEvent, index: number) => { e.preventDefault() const clientY = 'touches' in e ? e.touches[0].clientY : e.clientY dragStartY.current = clientY setDragIndex(index) setOverIndex(index) dragNodeRef.current = (e.target as HTMLElement).closest('[data-queue-row]') as HTMLElement }, []) const handleDragMove = useCallback((e: MouseEvent | TouchEvent) => { if (dragIndex === null || !listRef.current) return const clientY = 'touches' in e ? e.touches[0].clientY : e.clientY // Find which row we're over const rows = listRef.current.querySelectorAll('[data-queue-row]') for (let i = 0; i < rows.length; i++) { const rect = rows[i].getBoundingClientRect() if (clientY >= rect.top && clientY <= rect.bottom) { setOverIndex(i) break } } }, [dragIndex]) const handleDragEnd = useCallback(() => { if (dragIndex !== null && overIndex !== null && dragIndex !== overIndex) { moveInQueue(toAbsolute(dragIndex), toAbsolute(overIndex)) } setDragIndex(null) setOverIndex(null) dragNodeRef.current = null }, [dragIndex, overIndex, moveInQueue, upcomingStart]) // eslint-disable-line react-hooks/exhaustive-deps useEffect(() => { if (dragIndex === null) return const onMove = (e: MouseEvent | TouchEvent) => handleDragMove(e) const onEnd = () => handleDragEnd() window.addEventListener('mousemove', onMove) window.addEventListener('mouseup', onEnd) window.addEventListener('touchmove', onMove, { passive: false }) window.addEventListener('touchend', onEnd) return () => { window.removeEventListener('mousemove', onMove) window.removeEventListener('mouseup', onEnd) window.removeEventListener('touchmove', onMove) window.removeEventListener('touchend', onEnd) } }, [dragIndex, handleDragMove, handleDragEnd]) // Prevent body scroll when open useEffect(() => { if (open) { document.body.style.overflow = 'hidden' return () => { document.body.style.overflow = '' } } }, [open]) if (!open) return null const currentTrack = state.currentTrack const hasUpcoming = upcoming.length > 0 return (
{/* Header */}

Queue

{hasUpcoming ? ( ) : (
)}
{/* Now Playing */} {currentTrack && (

Now Playing

{currentTrack.coverArt ? ( {currentTrack.album} ) : (
)}
{currentTrack.title}
{currentTrack.artist}
)} {/* Next Up */} {hasUpcoming && (

Next Up

{upcoming.map((track, i) => { const isDragging = dragIndex === i const showIndicator = overIndex !== null && dragIndex !== null && overIndex !== dragIndex && overIndex === i return (
{/* Drop indicator line */} {showIndicator && dragIndex !== null && dragIndex > i && (
)}
{/* Drag handle */} {/* Track info — tap to jump */} {/* Remove button */}
{/* Drop indicator line (below) */} {showIndicator && dragIndex !== null && dragIndex < i && (
)}
) })}
)} {/* Empty state */} {!currentTrack && !hasUpcoming && (

Queue is empty

Search for songs to start listening

)} {/* Add Songs link */}
) }