diff --git a/src/app/darmasaba/(pages)/musik/musik-desa/page.tsx b/src/app/darmasaba/(pages)/musik/musik-desa/page.tsx index 7c8ee6e8..6368caf8 100644 --- a/src/app/darmasaba/(pages)/musik/musik-desa/page.tsx +++ b/src/app/darmasaba/(pages)/musik/musik-desa/page.tsx @@ -1,45 +1,116 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ 'use client' -import { ActionIcon, Avatar, Badge, Box, Card, Flex, Grid, Group, Paper, Slider, Stack, Text, TextInput } from '@mantine/core'; +import { ActionIcon, Avatar, Badge, Box, Card, Flex, Grid, Group, Paper, ScrollArea, Slider, Stack, Text, TextInput } from '@mantine/core'; import { IconArrowsShuffle, IconPlayerPauseFilled, IconPlayerPlayFilled, IconPlayerSkipBackFilled, IconPlayerSkipForwardFilled, IconRepeat, IconRepeatOff, IconSearch, IconVolume, IconVolumeOff, IconX } from '@tabler/icons-react'; -import { useEffect, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import BackButton from '../../desa/layanan/_com/BackButto'; +interface MusicFile { + id: string; + name: string; + realName: string; + path: string; + mimeType: string; + link: string; +} + +interface Musik { + id: string; + judul: string; + artis: string; + deskripsi: string | null; + durasi: string; + genre: string | null; + tahunRilis: number | null; + audioFile: MusicFile | null; + coverImage: MusicFile | null; + isActive: boolean; +} + const MusicPlayer = () => { const [isPlaying, setIsPlaying] = useState(false); const [currentTime, setCurrentTime] = useState(0); - const [duration, setDuration] = useState(245); + const [duration, setDuration] = useState(0); const [volume, setVolume] = useState(70); const [isMuted, setIsMuted] = useState(false); const [isRepeat, setIsRepeat] = useState(false); const [isShuffle, setIsShuffle] = useState(false); + const [search, setSearch] = useState(''); + const [musikData, setMusikData] = useState([]); + const [loading, setLoading] = useState(true); + const [currentSongIndex, setCurrentSongIndex] = useState(-1); - const songs = [ - { id: 1, title: 'Midnight Dreams', artist: 'The Wanderers', duration: '4:05', cover: 'https://images.unsplash.com/photo-1470225620780-dba8ba36b745?w=400&h=400&fit=crop' }, - { id: 2, title: 'Summer Breeze', artist: 'Coastal Vibes', duration: '3:42', cover: 'https://images.unsplash.com/photo-1493225457124-a3eb161ffa5f?w=400&h=400&fit=crop' }, - { id: 3, title: 'City Lights', artist: 'Urban Echo', duration: '4:18', cover: 'https://images.unsplash.com/photo-1514320291840-2e0a9bf2a9ae?w=400&h=400&fit=crop' }, - { id: 4, title: 'Ocean Waves', artist: 'Serenity Sound', duration: '5:20', cover: 'https://images.unsplash.com/photo-1459749411175-04bf5292ceea?w=400&h=400&fit=crop' }, - { id: 5, title: 'Neon Nights', artist: 'Electric Dreams', duration: '3:55', cover: 'https://images.unsplash.com/photo-1487180144351-b8472da7d491?w=400&h=400&fit=crop' }, - { id: 6, title: 'Mountain High', artist: 'Peak Performers', duration: '4:32', cover: 'https://images.unsplash.com/photo-1511671782779-c97d3d27a1d4?w=400&h=400&fit=crop' } - ]; - - const [currentSong, setCurrentSong] = useState(songs[0]); + const audioRef = useRef(null); + const progressInterval = useRef(null); + // Fetch musik data from API useEffect(() => { - let interval: any; - if (isPlaying) { - interval = setInterval(() => { - setCurrentTime(prev => { - if (prev >= duration) { - setIsPlaying(false); - return 0; - } - return prev + 1; - }); + const fetchMusik = async () => { + try { + setLoading(true); + const res = await fetch('/api/desa/musik/find-many?page=1&limit=50'); + const data = await res.json(); + if (data.success && data.data) { + const activeMusik = data.data.filter((m: Musik) => m.isActive); + setMusikData(activeMusik); + } + } catch (error) { + console.error('Error fetching musik:', error); + } finally { + setLoading(false); + } + }; + + fetchMusik(); + }, []); + + // Filter musik based on search + const filteredMusik = musikData.filter(musik => + musik.judul.toLowerCase().includes(search.toLowerCase()) || + musik.artis.toLowerCase().includes(search.toLowerCase()) || + (musik.genre && musik.genre.toLowerCase().includes(search.toLowerCase())) + ); + + const currentSong = currentSongIndex >= 0 && currentSongIndex < filteredMusik.length + ? filteredMusik[currentSongIndex] + : null; + + // Update progress bar + useEffect(() => { + if (isPlaying && audioRef.current) { + progressInterval.current = window.setInterval(() => { + if (audioRef.current) { + setCurrentTime(Math.floor(audioRef.current.currentTime)); + } }, 1000); + } else { + if (progressInterval.current) { + clearInterval(progressInterval.current); + } } - return () => clearInterval(interval); - }, [isPlaying, duration]); + + return () => { + if (progressInterval.current) { + clearInterval(progressInterval.current); + } + }; + }, [isPlaying]); + + // Update duration when song changes + useEffect(() => { + if (currentSong && audioRef.current) { + const durationParts = currentSong.durasi.split(':'); + const durationInSeconds = parseInt(durationParts[0]) * 60 + parseInt(durationParts[1]); + setDuration(durationInSeconds); + setCurrentTime(0); + if (isPlaying) { + audioRef.current.play().catch(err => { + console.error('Error playing audio:', err); + setIsPlaying(false); + }); + } + } + }, [currentSongIndex]); const formatTime = (seconds: number) => { const mins = Math.floor(seconds / 60); @@ -47,20 +118,115 @@ const MusicPlayer = () => { return `${mins}:${secs.toString().padStart(2, '0')}`; }; - const playSong = (song: any) => { - setCurrentSong(song); - setCurrentTime(0); + const playSong = (index: number) => { + if (index < 0 || index >= filteredMusik.length) return; + + setCurrentSongIndex(index); setIsPlaying(true); - const durationInSeconds = parseInt(song.duration.split(':')[0]) * 60 + parseInt(song.duration.split(':')[1]); - setDuration(durationInSeconds); + }; + + const handleSongEnd = () => { + if (isRepeat) { + if (audioRef.current) { + audioRef.current.currentTime = 0; + audioRef.current.play(); + } + } else { + // Play next song + let nextIndex: number; + if (isShuffle) { + nextIndex = Math.floor(Math.random() * filteredMusik.length); + } else { + nextIndex = (currentSongIndex + 1) % filteredMusik.length; + } + + if (filteredMusik.length > 1) { + playSong(nextIndex); + } else { + setIsPlaying(false); + setCurrentTime(0); + } + } + }; + + const handleSeek = (value: number) => { + setCurrentTime(value); + if (audioRef.current) { + audioRef.current.currentTime = value; + } }; const toggleMute = () => { - setIsMuted(!isMuted); + const newMuted = !isMuted; + setIsMuted(newMuted); + if (audioRef.current) { + audioRef.current.muted = newMuted; + } }; + const handleVolumeChange = (val: number) => { + setVolume(val); + if (audioRef.current) { + audioRef.current.volume = val / 100; + } + if (val > 0 && isMuted) { + setIsMuted(false); + } + }; + + const skipBack = () => { + if (audioRef.current) { + audioRef.current.currentTime = Math.max(0, audioRef.current.currentTime - 10); + } + }; + + const skipForward = () => { + if (audioRef.current) { + audioRef.current.currentTime = Math.min(duration, audioRef.current.currentTime + 10); + } + }; + + const togglePlayPause = () => { + if (!currentSong) return; + + if (isPlaying) { + audioRef.current?.pause(); + setIsPlaying(false); + } else { + audioRef.current?.play().catch(err => { + console.error('Error playing audio:', err); + }); + setIsPlaying(true); + } + }; + + if (loading) { + return ( + + + Memuat data musik... + + + ); + } + return ( + {/* Hidden audio element */} + {currentSong?.audioFile && ( +