feat(berita): add multiple images gallery and YouTube video support
- Update schema: add images relation list and linkVideo field - API: support multiple image upload and YouTube link in create/update - Admin create page: add gallery upload (max 10) and YouTube embed preview - Admin edit page: manage existing/new gallery images and YouTube link - Admin detail page: display gallery grid and YouTube video embed - Public detail page: show gallery images and YouTube video with responsive layout - State: add imageIds[] and linkVideo fields with proper type handling - Music player: fix seek functionality and ESLint warnings Breaking changes: - Prisma schema updated - requires migration - API create/update endpoints now expect imageIds array and linkVideo string Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
@@ -8,8 +8,7 @@ export function useAudioProgress(
|
||||
audioRef: React.RefObject<HTMLAudioElement>,
|
||||
isPlaying: boolean,
|
||||
setCurrentTime: (time: number) => void,
|
||||
isSeekingRef: React.RefObject<boolean>,
|
||||
lastSeekTimeRef?: React.RefObject<number>
|
||||
isSeekingRef: React.RefObject<boolean>
|
||||
) {
|
||||
const rafRef = useRef<number | null>(null);
|
||||
const lastTimeRef = useRef<number>(0);
|
||||
|
||||
@@ -50,7 +50,7 @@ const MusicPlayer = () => {
|
||||
const lastSeekTimeRef = useRef<number>(0); // Track last seek time
|
||||
|
||||
// Smooth progress update dengan requestAnimationFrame
|
||||
useAudioProgress(audioRef as React.RefObject<HTMLAudioElement>, isPlaying, setCurrentTime, isSeekingRef, lastSeekTimeRef);
|
||||
useAudioProgress(audioRef as React.RefObject<HTMLAudioElement>, isPlaying, setCurrentTime, isSeekingRef);
|
||||
|
||||
// Fetch musik data from API
|
||||
useEffect(() => {
|
||||
@@ -108,7 +108,6 @@ const MusicPlayer = () => {
|
||||
// }, [isPlaying]);
|
||||
|
||||
// Update duration when song changes (HANYA saat ganti lagu, bukan saat isPlaying berubah)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
useEffect(() => {
|
||||
if (currentSong && audioRef.current) {
|
||||
// Cek apakah ini benar-benar lagu baru
|
||||
@@ -136,10 +135,9 @@ const MusicPlayer = () => {
|
||||
}
|
||||
// Jika bukan lagu baru, jangan reset currentTime (biar seek tidak kembali ke 0)
|
||||
}
|
||||
}, [currentSong?.id]);
|
||||
}, [currentSong?.id]); // Intentional: hanya depend on song ID, bukan isPlaying
|
||||
|
||||
// Sync duration dari audio element jika berbeda signifikan (> 1 detik)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
useEffect(() => {
|
||||
const audio = audioRef.current;
|
||||
if (!audio || !currentSong) return;
|
||||
@@ -157,7 +155,7 @@ const MusicPlayer = () => {
|
||||
|
||||
audio.addEventListener('loadedmetadata', handleLoadedMetadata);
|
||||
return () => audio.removeEventListener('loadedmetadata', handleLoadedMetadata);
|
||||
}, [currentSong?.id]);
|
||||
}, [currentSong?.id]); // Intentional: hanya depend on song ID
|
||||
|
||||
const formatTime = (seconds: number) => {
|
||||
const mins = Math.floor(seconds / 60);
|
||||
|
||||
Reference in New Issue
Block a user