order detail + types + components
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
import { Pause, Play } from "iconsax-react"
|
||||
import { useEffect, useRef, useState, type FC } from "react"
|
||||
|
||||
type VoicePlayerProps = {
|
||||
url: string
|
||||
}
|
||||
|
||||
const VoicePlayer: FC<VoicePlayerProps> = ({ url }) => {
|
||||
const audioRef = useRef<HTMLAudioElement | null>(null)
|
||||
const [isPlaying, setIsPlaying] = useState(false)
|
||||
const [progress, setProgress] = useState(0)
|
||||
|
||||
useEffect(() => {
|
||||
const audio = audioRef.current
|
||||
if (!audio) return
|
||||
|
||||
const update = () => {
|
||||
if (!audio.duration) return
|
||||
setProgress(audio.currentTime / audio.duration)
|
||||
}
|
||||
|
||||
audio.addEventListener('timeupdate', update)
|
||||
audio.addEventListener('ended', () => {
|
||||
setIsPlaying(false)
|
||||
setProgress(0)
|
||||
})
|
||||
|
||||
return () => {
|
||||
audio.removeEventListener('timeupdate', update)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const toggle = () => {
|
||||
if (!audioRef.current) return
|
||||
if (isPlaying) audioRef.current.pause()
|
||||
else audioRef.current.play()
|
||||
setIsPlaying(!isPlaying)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-full h-12 bg-white border border-border rounded-xl flex items-center px-3 gap-3 mt-2">
|
||||
<button
|
||||
onClick={toggle}
|
||||
className="w-8 h-8 rounded-full bg-black flex items-center justify-center flex-shrink-0"
|
||||
>
|
||||
{isPlaying ? (
|
||||
<Pause size={16} color="#fff" variant="Bold" />
|
||||
) : (
|
||||
<Play size={16} color="#fff" variant="Bold" />
|
||||
)}
|
||||
</button>
|
||||
|
||||
<div className="flex-1 flex items-center gap-[2px] h-8">
|
||||
{Array.from({ length: 60 }).map((_, i) => {
|
||||
const passed = i / 60 <= progress
|
||||
return (
|
||||
<div
|
||||
key={i}
|
||||
className="w-[2px] rounded-full transition-all"
|
||||
style={{
|
||||
height: `${Math.random() * 18 + 4}px`,
|
||||
backgroundColor: passed ? '#0047FF' : '#E5E7EB'
|
||||
}}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
<audio ref={audioRef} src={url} className="hidden" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default VoicePlayer
|
||||
Reference in New Issue
Block a user