NLP-IBM-Debater / src /app /components /chat /AudioPlayer.tsx
Yassine Mhirsi
auto play audio
3beb9d7
import React, { useState, useRef, useEffect } from 'react';
import { Play, Pause } from 'lucide-react';
type AudioPlayerProps = {
src: string;
className?: string;
autoPlay?: boolean; // Whether to auto-play the audio when rendered
};
const AudioPlayer: React.FC<AudioPlayerProps> = ({ src, className = '', autoPlay = false }) => {
const [isPlaying, setIsPlaying] = useState(false);
const [duration, setDuration] = useState(0);
const [currentTime, setCurrentTime] = useState(0);
const audioRef = useRef<HTMLAudioElement>(null);
const progressRef = useRef<HTMLDivElement>(null);
const hasAutoPlayedRef = useRef(false); // To track if auto-play has already happened
useEffect(() => {
const audio = audioRef.current;
if (!audio) return;
const setAudioData = () => {
setDuration(audio.duration);
setCurrentTime(audio.currentTime);
};
const setAudioTime = () => setCurrentTime(audio.currentTime);
if (audio.readyState >= 1) {
// Metadata is loaded
setAudioData();
}
audio.addEventListener('loadeddata', setAudioData);
audio.addEventListener('timeupdate', setAudioTime);
// Auto-play when the component mounts if autoPlay is true and hasn't played yet
if (autoPlay && !hasAutoPlayedRef.current) {
const playAudio = async () => {
try {
await audio.play();
setIsPlaying(true);
hasAutoPlayedRef.current = true; // Mark as auto-played to prevent re-triggering
} catch (error) {
// Handle browser auto-play restrictions gracefully
console.warn('Auto-play failed:', error);
}
};
playAudio();
}
return () => {
audio.removeEventListener('loadeddata', setAudioData);
audio.removeEventListener('timeupdate', setAudioTime);
};
}, [src, autoPlay]); // Only re-run when src or autoPlay changes
const togglePlayPause = () => {
const audio = audioRef.current;
if (!audio) return;
if (isPlaying) {
audio.pause();
} else {
audio.play();
}
setIsPlaying(!isPlaying);
};
const handleProgressClick = (e: React.MouseEvent<HTMLDivElement>) => {
const audio = audioRef.current;
if (!audio || !progressRef.current) return;
const progressBar = progressRef.current;
const clickX = e.nativeEvent.offsetX;
const width = progressBar.clientWidth;
const newTime = (clickX / width) * duration;
audio.currentTime = newTime;
setCurrentTime(newTime);
};
const formatTime = (time: number) => {
if (isNaN(time)) return '0:00';
const minutes = Math.floor(time / 60);
const seconds = Math.floor(time % 60);
return `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
};
const progress = duration ? (currentTime / duration) * 100 : 0;
return (
<div className={`bg-black/10 dark:bg-gray-800/50 backdrop-blur-sm rounded-xl p-3 ${className}`}>
<audio
ref={audioRef}
src={src}
onEnded={() => setIsPlaying(false)}
onPlay={() => setIsPlaying(true)}
onPause={() => setIsPlaying(false)}
/>
<div className="flex items-center gap-3">
<button
onClick={togglePlayPause}
className="flex items-center justify-center w-8 h-8 rounded-full bg-teal-500 hover:bg-teal-600 text-white transition-colors"
>
{isPlaying ? (
<Pause className="w-4 h-4" />
) : (
<Play className="w-4 h-4 ml-0.5" />
)}
</button>
<div className="flex-1">
<div
ref={progressRef}
onClick={handleProgressClick}
className="h-1.5 bg-gray-300 dark:bg-gray-700 rounded-full cursor-pointer overflow-hidden"
>
<div
className="h-full bg-teal-500 rounded-full"
style={{ width: `${progress}%` }}
/>
</div>
<div className="flex justify-between text-xs text-gray-500 dark:text-white mt-1">
<span>{formatTime(currentTime)}</span>
<span>{formatTime(duration)}</span>
</div>
</div>
</div>
</div>
);
};
export default AudioPlayer;