'use client'; import React, { useState, useRef, useEffect } from 'react'; import type { Queue, PlayHistory } from '../types/api'; import { API_PATHS } from '../types/api'; interface AudioPlayerProps { currentSong?: { id: string; title: string; artist: string; duration: number; url: string; }; queue?: Queue; isPlaying?: boolean; volume?: number; currentTime?: number; onPlay?: () => void; onPause?: () => void; onNext?: () => void; onPrevious?: () => void; onSeek?: (time: number) => void; onVolumeChange?: (volume: number) => void; onQueueUpdate?: (queue: Queue) => void; } type RepeatMode = 'none' | 'one' | 'all'; export default function AudioPlayer({ currentSong, queue, isPlaying = false, volume = 0.7, currentTime = 0, onPlay, onPause, onNext, onPrevious, onSeek, onVolumeChange, onQueueUpdate, }: AudioPlayerProps) { const [localVolume, setLocalVolume] = useState(volume); const [localCurrentTime, setLocalCurrentTime] = useState(currentTime); const [repeatMode, setRepeatMode] = useState('none'); const [isShuffled, setIsShuffled] = useState(false); const [isMuted, setIsMuted] = useState(false); const [showQueue, setShowQueue] = useState(false); const audioRef = useRef(null); const progressBarRef = useRef(null); // Sync with props useEffect(() => { setLocalVolume(volume); }, [volume]); useEffect(() => { setLocalCurrentTime(currentTime); }, [currentTime]); // Format time helper const formatTime = (seconds: number): string => { const mins = Math.floor(seconds / 60); const secs = Math.floor(seconds % 60); return `${mins}:${secs.toString().padStart(2, '0')}`; }; // API calls with proper error handling const handlePlay = async () => { try { const response = await fetch(API_PATHS.PLAYER_PLAY, { method: 'POST', headers: { 'Content-Type': 'application/json' }, }); if (!response.ok) { throw new Error('Failed to play'); } onPlay?.(); } catch (error) { console.error('Play error:', error); } }; const handlePause = async () => { try { const response = await fetch(API_PATHS.PLAYER_PAUSE, { method: 'POST', headers: { 'Content-Type': 'application/json' }, }); if (!response.ok) { throw new Error('Failed to pause'); } onPause?.(); } catch (error) { console.error('Pause error:', error); } }; const handleNext = async () => { try { const response = await fetch(API_PATHS.PLAYER_NEXT, { method: 'POST', headers: { 'Content-Type': 'application/json' }, }); if (!response.ok) { throw new Error('Failed to play next'); } onNext?.(); } catch (error) { console.error('Next error:', error); } }; const handlePrevious = async () => { try { const response = await fetch(API_PATHS.PLAYER_PREVIOUS, { method: 'POST', headers: { 'Content-Type': 'application/json' }, }); if (!response.ok) { throw new Error('Failed to play previous'); } onPrevious?.(); } catch (error) { console.error('Previous error:', error); } }; const handleVolumeChange = async (newVolume: number) => { try { setLocalVolume(newVolume); setIsMuted(newVolume === 0); onVolumeChange?.(newVolume); // Volume change would typically be handled client-side // But we could persist it to user preferences } catch (error) { console.error('Volume change error:', error); } }; const handleSeek = (time: number) => { setLocalCurrentTime(time); onSeek?.(time); if (audioRef.current) { audioRef.current.currentTime = time; } }; const handleProgressClick = (e: React.MouseEvent) => { if (!progressBarRef.current || !currentSong) return; const rect = progressBarRef.current.getBoundingClientRect(); const percent = (e.clientX - rect.left) / rect.width; const newTime = percent * currentSong.duration; handleSeek(newTime); }; const toggleRepeat = () => { const modes: RepeatMode[] = ['none', 'one', 'all']; const currentIndex = modes.indexOf(repeatMode); const nextMode = modes[(currentIndex + 1) % modes.length]; setRepeatMode(nextMode); }; const toggleShuffle = () => { setIsShuffled(!isShuffled); }; const toggleMute = () => { if (isMuted) { handleVolumeChange(volume); } else { handleVolumeChange(0); } }; const fetchQueue = async () => { try { const response = await fetch(API_PATHS.PLAYER_QUEUE); if (response.ok) { const queueData: Queue = await response.json(); onQueueUpdate?.(queueData); } } catch (error) { console.error('Failed to fetch queue:', error); } }; // Progress percentage const progressPercent = currentSong ? (localCurrentTime / currentSong.duration) * 100 : 0; return (
{/* Audio element for actual playback */} {currentSong && (