import { Button } from '@/components/ui/button' import { Progress } from '@/components/ui/progress' import { filesService } from '@/lib/api/services/files' import { type MessageResponse, type PlayerState, playerService, } from '@/lib/api/services/player' import { PLAYER_EVENTS, playerEvents } from '@/lib/events' import { cn } from '@/lib/utils' import { formatDuration } from '@/utils/format-duration' import { Maximize2, Music, Pause, Play, SkipBack, SkipForward, Volume2, VolumeX, } from 'lucide-react' import { useCallback, useEffect, useState } from 'react' import { toast } from 'sonner' interface CompactPlayerProps { className?: string } export function CompactPlayer({ className }: CompactPlayerProps) { const [state, setState] = useState({ status: 'stopped', mode: 'continuous', volume: 80, previous_volume: 80, position: 0, }) const [isLoading, setIsLoading] = useState(false) // Load initial state useEffect(() => { const loadState = async () => { try { const initialState = await playerService.getState() setState(initialState) } catch (error) { console.error('Failed to load player state:', error) } } loadState() }, []) // Listen for player state updates useEffect(() => { const handlePlayerState = (newState: PlayerState) => { setState(newState) } playerEvents.on(PLAYER_EVENTS.PLAYER_STATE, handlePlayerState) return () => { playerEvents.off(PLAYER_EVENTS.PLAYER_STATE, handlePlayerState) } }, []) const executeAction = useCallback( async ( action: () => Promise, actionName: string, ) => { setIsLoading(true) try { await action() } catch (error) { console.error(`Failed to ${actionName}:`, error) toast.error(`Failed to ${actionName}`) } finally { setIsLoading(false) } }, [], ) const handlePlayPause = useCallback(() => { if (state.status === 'playing') { executeAction(playerService.pause, 'pause') } else { executeAction(playerService.play, 'play') } }, [state.status, executeAction]) const handlePrevious = useCallback(() => { executeAction(playerService.previous, 'go to previous track') }, [executeAction]) const handleNext = useCallback(() => { executeAction(playerService.next, 'go to next track') }, [executeAction]) const handleVolumeToggle = useCallback(() => { if (state.volume === 0) { // Unmute executeAction(playerService.unmute, 'unmute') } else { // Mute executeAction(playerService.mute, 'mute') } }, [state.volume, executeAction]) // // Don't show if no current sound // if (!state.current_sound) { // return null // } return (
{/* Collapsed state - only play/pause button */}
{/* Expanded state - full player */}
{/* Track Info */}
{state.current_sound?.thumbnail ? ( {state.current_sound.name} { // Hide image and show music icon if thumbnail fails to load const target = e.target as HTMLImageElement target.style.display = 'none' const musicIcon = target.nextElementSibling as HTMLElement if (musicIcon) musicIcon.style.display = 'block' }} /> ) : null}
{state.current_sound?.name || 'No track selected'}
{state.playlist?.name}
{/* Progress Bar */}
{formatDuration(state.position)} {formatDuration(state.duration || 0)}
{/* Controls */}
) }