diff --git a/web/src/components/AudioPlayer.tsx b/web/src/components/AudioPlayer.tsx
index c05dbc4cc..a9fdf1103 100644
--- a/web/src/components/AudioPlayer.tsx
+++ b/web/src/components/AudioPlayer.tsx
@@ -18,6 +18,12 @@ const AudioPlayer = ({ src, className = "" }: Props) => {
const audio = audioRef.current;
if (!audio) return;
+ // Reset state when src changes
+ setIsPlaying(false);
+ setCurrentTime(0);
+ setDuration(0);
+ setIsLoading(true);
+
const handleLoadedMetadata = () => {
if (audio.duration && !isNaN(audio.duration) && isFinite(audio.duration)) {
setDuration(audio.duration);
@@ -57,7 +63,22 @@ const AudioPlayer = ({ src, className = "" }: Props) => {
audio.removeEventListener("timeupdate", handleTimeUpdate);
audio.removeEventListener("ended", handleEnded);
};
- }, []);
+ }, [src]);
+
+ useEffect(() => {
+ const handlePlayAudio = (e: Event) => {
+ const customEvent = e as CustomEvent;
+ if (customEvent.detail !== audioRef.current && isPlaying) {
+ audioRef.current?.pause();
+ setIsPlaying(false);
+ }
+ };
+
+ document.addEventListener("play-audio", handlePlayAudio);
+ return () => {
+ document.removeEventListener("play-audio", handlePlayAudio);
+ };
+ }, [isPlaying]);
const togglePlayPause = async () => {
const audio = audioRef.current;
@@ -68,6 +89,10 @@ const AudioPlayer = ({ src, className = "" }: Props) => {
setIsPlaying(false);
} else {
try {
+ // Stop other audio players
+ const event = new CustomEvent("play-audio", { detail: audio });
+ document.dispatchEvent(event);
+
await audio.play();
setIsPlaying(true);
} catch (error) {
@@ -97,30 +122,29 @@ const AudioPlayer = ({ src, className = "" }: Props) => {
return (
-
-
-
- {formatTime(currentTime)} / {formatTime(duration)}
-
-
-
-
+
+
+
+ {formatTime(currentTime)} / {formatTime(duration)}
+
);
};
diff --git a/web/src/components/MemoEditor/ActionButton/InsertMenu.tsx b/web/src/components/MemoEditor/ActionButton/InsertMenu.tsx
index 1fea285b3..ed320b4fe 100644
--- a/web/src/components/MemoEditor/ActionButton/InsertMenu.tsx
+++ b/web/src/components/MemoEditor/ActionButton/InsertMenu.tsx
@@ -1,6 +1,18 @@
import { LatLng } from "leaflet";
import { uniqBy } from "lodash-es";
-import { FileIcon, LinkIcon, LoaderIcon, MapPinIcon, Maximize2Icon, MicIcon, MoreHorizontalIcon, PlusIcon, XIcon } from "lucide-react";
+import {
+ FileIcon,
+ LinkIcon,
+ LoaderIcon,
+ MapPinIcon,
+ Maximize2Icon,
+ MicIcon,
+ MoreHorizontalIcon,
+ PauseIcon,
+ PlayIcon,
+ PlusIcon,
+ XIcon,
+} from "lucide-react";
import { observer } from "mobx-react-lite";
import { useContext, useState } from "react";
import { toast } from "react-hot-toast";
@@ -136,7 +148,7 @@ const InsertMenu = observer((props: Props) => {
context.setAttachmentList([...context.attachmentList, attachment]);
} catch (error: any) {
console.error("Failed to upload audio recording:", error);
- toast.error(error.details || "Failed to upload audio recording");
+ toast.error(error.message || "Failed to upload audio recording");
}
};
@@ -148,13 +160,31 @@ const InsertMenu = observer((props: Props) => {
{new Date(audioRecorder.recordingTime * 1000).toISOString().substring(14, 19)}
-