feat: add refresh icon to voice msg
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#101828" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M23 3.99995V9.99995M23 9.99995H17M23 9.99995L18.36 5.63995C17.2853 4.56467 15.9556 3.77916 14.4952 3.35673C13.0348 2.93429 11.4911 2.8887 10.0083 3.22421C8.52547 3.55972 7.1518 4.26539 6.01547 5.27537C4.87913 6.28536 4.01717 7.56674 3.51 8.99995M1 20V14M1 14H7M1 14L5.64 18.36C6.71475 19.4352 8.04437 20.2207 9.50481 20.6432C10.9652 21.0656 12.5089 21.1112 13.9917 20.7757C15.4745 20.4402 16.8482 19.7345 17.9845 18.7245C19.1209 17.7145 19.9828 16.4332 20.49 15" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 659 B |
@@ -3,6 +3,7 @@ import dayjs from 'dayjs';
|
|||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import WaveSurfer from 'wavesurfer.js';
|
import WaveSurfer from 'wavesurfer.js';
|
||||||
import IconPause from '../../assets/icons/pause.svg';
|
import IconPause from '../../assets/icons/pause.svg';
|
||||||
|
import IconRefresh from '../../assets/icons/refresh.svg';
|
||||||
import IconPlay from '../../assets/icons/play.circle.svg';
|
import IconPlay from '../../assets/icons/play.circle.svg';
|
||||||
import BASE_URL from '../../app/config';
|
import BASE_URL from '../../app/config';
|
||||||
|
|
||||||
@@ -21,14 +22,13 @@ const VoiceMessage = ({ file_path }: { file_path: string }) => {
|
|||||||
// const [audio, setAudio] = useState<HTMLAudioElement>(new Audio(`${BASE_URL}/resource/file?file_path=${encodeURIComponent(
|
// const [audio, setAudio] = useState<HTMLAudioElement>(new Audio(`${BASE_URL}/resource/file?file_path=${encodeURIComponent(
|
||||||
// file_path
|
// file_path
|
||||||
// )}`));
|
// )}`));
|
||||||
useEffect(() => {
|
const initWave = (file_path: string) => {
|
||||||
let wave: WaveSurfer | null = null;
|
let wave: WaveSurfer | null = null;
|
||||||
if (containerRef.current && file_path) {
|
|
||||||
const audioSrc = `${BASE_URL}/resource/file?file_path=${encodeURIComponent(
|
const audioSrc = `${BASE_URL}/resource/file?file_path=${encodeURIComponent(
|
||||||
file_path
|
file_path
|
||||||
)}`;
|
)}`;
|
||||||
wave = WaveSurfer.create({
|
wave = WaveSurfer.create({
|
||||||
container: containerRef.current,
|
container: containerRef.current ?? "",
|
||||||
// maxCanvasWidth: 200,
|
// maxCanvasWidth: 200,
|
||||||
height: 32,
|
height: 32,
|
||||||
waveColor: '#0BA5EC',
|
waveColor: '#0BA5EC',
|
||||||
@@ -43,6 +43,9 @@ const VoiceMessage = ({ file_path }: { file_path: string }) => {
|
|||||||
wave.on('error', function (err) {
|
wave.on('error', function (err) {
|
||||||
console.log("voice message error", err);
|
console.log("voice message error", err);
|
||||||
setStatus("error");
|
setStatus("error");
|
||||||
|
if (waveRef.current) {
|
||||||
|
waveRef.current.destroy();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
wave.on('play', function () {
|
wave.on('play', function () {
|
||||||
setPlaying(true);
|
setPlaying(true);
|
||||||
@@ -62,6 +65,11 @@ const VoiceMessage = ({ file_path }: { file_path: string }) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
waveRef.current = wave;
|
waveRef.current = wave;
|
||||||
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
if (containerRef.current && file_path) {
|
||||||
|
initWave(file_path);
|
||||||
}
|
}
|
||||||
return () => {
|
return () => {
|
||||||
if (waveRef.current) {
|
if (waveRef.current) {
|
||||||
@@ -78,16 +86,21 @@ const VoiceMessage = ({ file_path }: { file_path: string }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const handleReload = () => {
|
||||||
|
initWave(file_path);
|
||||||
|
};
|
||||||
|
const notReady = status !== "ready";
|
||||||
return (
|
return (
|
||||||
<div className={clsx("select-none flex items-center gap-2 p-2 rounded-lg max-w-sm", status === "error" ? "bg-red-200" : "bg-primary-100 dark:bg-primary-900")}>
|
<div className={clsx("relative select-none flex items-center gap-2 p-2 rounded-lg max-w-sm", status === "error" ? "bg-red-200" : "bg-primary-100 dark:bg-primary-900")}>
|
||||||
<button className='disabled:opacity-60' onClick={handleClick} disabled={status !== "ready"}>
|
<button className='disabled:opacity-60' onClick={handleClick} disabled={notReady}>
|
||||||
{playing ? <IconPause className="stroke-primary-500" /> : <IconPlay className="stroke-primary-500" />}
|
{playing ? <IconPause className="stroke-primary-500" /> : <IconPlay className="stroke-primary-500" />}
|
||||||
</button>
|
</button>
|
||||||
<div ref={containerRef} className='flex-1 h-8' >
|
<div ref={containerRef} className={clsx('flex-1 h-8', notReady && "flex-center")} >
|
||||||
{status == "loading" && <span className='text-xs'>Loading voice message...</span>}
|
{status == "loading" && <span className='text-xs'>Loading voice message...</span>}
|
||||||
{status == "error" && <span className='text-xs text-red-800'>Load voice message error</span>}
|
{status == "error" && <span className='text-xs text-red-800'>Load voice message error</span>}
|
||||||
</div>
|
</div>
|
||||||
<time className='text-primary-500 text-xs whitespace-nowrap text-left'>{duration}'</time>
|
{status !== "error" && <time className='text-primary-500 text-xs whitespace-nowrap text-left'>{duration}'</time>}
|
||||||
|
{status === "error" && <IconRefresh role="button" className="absolute -right-6 top-1/2 -translate-y-1/2 w-4 h-4 stroke-primary-600" onClick={handleReload} />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user