- {!values.soundFile && (
-
- No uploaded sound files
-
- )}
Uploaded Sound files will appear in the drop downs once they are
uploaded. They can be used for any Sighting,{" "}
diff --git a/src/components/SightingsWidget/SightingWidget.tsx b/src/components/SightingsWidget/SightingWidget.tsx
index 2ff85b1..9548880 100644
--- a/src/components/SightingsWidget/SightingWidget.tsx
+++ b/src/components/SightingsWidget/SightingWidget.tsx
@@ -1,6 +1,6 @@
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import type { HitKind, QueuedHit, ReducedSightingType, SightingType } from "../../types/types";
-import { BLANK_IMG, getSoundFileURL } from "../../utils/utils";
+import { BLANK_IMG } from "../../utils/utils";
import NumberPlate from "../PlateStack/NumberPlate";
import Card from "../UI/Card";
import CardHeader from "../UI/CardHeader";
@@ -19,6 +19,7 @@ import { useIntegrationsContext } from "../../context/IntegrationsContext";
import { useSoundContext } from "../../context/SoundContext";
import Loading from "../UI/Loading";
import { checkIsHotListHit, getNPEDCategory } from "../../utils/utils";
+import { useCachedSoundSrc } from "../../hooks/usecachedSoundSrc";
function useNow(tickMs = 1000) {
const [, setNow] = useState(() => Date.now());
@@ -43,21 +44,8 @@ export default function SightingHistoryWidget({ className, title }: SightingHist
useNow(1000);
const { state } = useSoundContext();
- const soundSrcNped = useMemo(() => {
- if (state?.NPEDsound?.includes(".mp3") || state.NPEDsound?.includes(".wav")) {
- const file = state.soundOptions?.find((item) => item.name === state.NPEDsound);
- return file?.soundUrl ?? popup;
- }
- return getSoundFileURL(state.NPEDsound) ?? popup;
- }, [state.NPEDsound, state.soundOptions]);
-
- const soundSrcHotlist = useMemo(() => {
- if (state?.hotlistSound?.includes(".mp3") || state.hotlistSound?.includes(".wav")) {
- const file = state.soundOptions?.find((item) => item.name === state.hotlistSound);
- return file?.soundUrl ?? notification;
- }
- return getSoundFileURL(state?.hotlistSound) ?? notification;
- }, [state.hotlistSound, state.soundOptions]);
+ const { src: soundSrcHotlist } = useCachedSoundSrc(state?.hotlistSound, notification);
+ const { src: soundSrcNped } = useCachedSoundSrc(state?.NPEDsound, popup);
const { play: npedSound } = useSound(soundSrcNped, { volume: state.NPEDsoundVolume });
const { play: hotlistsound } = useSound(soundSrcHotlist, { volume: state.hotlistSoundVolume });
@@ -181,8 +169,8 @@ export default function SightingHistoryWidget({ className, title }: SightingHist
if (!isSightingModalOpen && modalQueue.length > 0) {
const next = modalQueue[0];
- // if (next.kind === "NPED") npedSound();
- // else hotlistsound();
+ if (next.kind === "NPED") npedSound();
+ else hotlistsound();
setSelectedSighting(next.sighting);
setSightingModalOpen(true);
diff --git a/src/hooks/useSightingFeed.ts b/src/hooks/useSightingFeed.ts
index 30283f2..2524041 100644
--- a/src/hooks/useSightingFeed.ts
+++ b/src/hooks/useSightingFeed.ts
@@ -1,14 +1,14 @@
-import { useEffect, useMemo, useRef, useState } from "react";
+import { useEffect, useRef, useState } from "react";
import { useDebouncedCallback } from "use-debounce";
import { Query, useQuery } from "@tanstack/react-query";
import type { SightingType } from "../types/types";
import { useSound } from "react-sounds";
import { useSoundContext } from "../context/SoundContext";
-import { checkIsHotListHit, getNPEDCategory, getSoundFileURL } from "../utils/utils";
+import { checkIsHotListHit, getNPEDCategory } from "../utils/utils";
import switchSound from "../assets/sounds/ui/switch.mp3";
import notification from "../assets/sounds/ui/notification.mp3";
import popup from "../assets/sounds/ui/popup_open.mp3";
-import { useFileUpload } from "./useFileUpload";
+import { useCachedSoundSrc } from "./usecachedSoundSrc";
async function fetchSighting(url: string | undefined, ref: number): Promise {
const res = await fetch(`${url}${ref}`, {
@@ -19,53 +19,15 @@ async function fetchSighting(url: string | undefined, ref: number): Promise([]);
const [selectedRef, setSelectedRef] = useState(null);
const [sessionStarted, setSessionStarted] = useState(false);
const [selectedSighting, setSelectedSighting] = useState(null);
- const isUploaded = state?.sightingSound?.endsWith(".mp3") || state?.sightingSound?.endsWith(".wav");
-
- const fileName = isUploaded ? state.sightingSound : switchSound;
-
- const { query: fileQuery } = useFileUpload({
- queryKey: fileName ? [fileName] : undefined,
- });
-
- const objUrlRef = useRef(null);
-
- const soundSrcHotlist = useMemo(() => {
- if (state?.hotlistSound?.includes(".mp3") || state.hotlistSound?.includes(".wav")) {
- const file = state.soundOptions?.find((item) => item.name === state.hotlistSound);
- return file?.soundUrl ?? notification;
- }
- return getSoundFileURL(state?.hotlistSound) ?? notification;
- }, [state.hotlistSound, state.soundOptions]);
-
- const soundSrcNped = useMemo(() => {
- if (state?.NPEDsound?.includes(".mp3") || state.NPEDsound?.includes(".wav")) {
- const file = state.soundOptions?.find((item) => item.name === state.NPEDsound);
- return file?.soundUrl ?? popup;
- }
- return getSoundFileURL(state.NPEDsound) ?? popup;
- }, [state.NPEDsound, state.soundOptions]);
-
- const soundSrc = useMemo(() => {
- if (isUploaded && fileQuery?.data instanceof Blob) {
- if (objUrlRef.current) URL.revokeObjectURL(objUrlRef.current);
- objUrlRef.current = URL.createObjectURL(fileQuery.data);
- console.log(fileQuery.data);
- return objUrlRef.current;
- }
- return getSoundFileURL(state?.sightingSound) ?? switchSound;
- }, [isUploaded, fileQuery?.data, state?.sightingSound]);
-
- useEffect(() => {
- return () => {
- if (objUrlRef.current) URL.revokeObjectURL(objUrlRef.current);
- };
- }, []);
+ const { src: soundSrc } = useCachedSoundSrc(state?.sightingSound, switchSound);
+ const { src: soundSrcHotlist } = useCachedSoundSrc(state?.hotlistSound, notification);
+ const { src: soundSrcNped } = useCachedSoundSrc(state?.NPEDsound, popup);
const { play: hotlistsound } = useSound(soundSrcHotlist, { volume: state.hotlistSoundVolume });
const { play: npedSound } = useSound(soundSrcNped, { volume: state.NPEDsoundVolume });
diff --git a/src/hooks/usecachedSoundSrc.ts b/src/hooks/usecachedSoundSrc.ts
new file mode 100644
index 0000000..192998e
--- /dev/null
+++ b/src/hooks/usecachedSoundSrc.ts
@@ -0,0 +1,48 @@
+import { useEffect, useMemo, useRef, useState } from "react";
+import { useFileUpload } from "./useFileUpload";
+import { getSoundFileURL } from "../utils/utils";
+
+export function useCachedSoundSrc(selected: string | undefined, fallbackUrl: string) {
+ const isUploaded = !!selected && (selected.endsWith(".mp3") || selected.endsWith(".wav"));
+ const fileName = isUploaded ? selected : undefined;
+
+ const { query } = useFileUpload({
+ queryKey: fileName ? [fileName] : undefined,
+ });
+
+ const [objectUrl, setObjectUrl] = useState();
+ const objRef = useRef(null);
+
+ useEffect(() => {
+ const blob = query?.data;
+ if (blob instanceof Blob) {
+ if (objRef.current) URL.revokeObjectURL(objRef.current);
+ const url = URL.createObjectURL(blob);
+ objRef.current = url;
+ setObjectUrl(url);
+ } else {
+ if (objRef.current) URL.revokeObjectURL(objRef.current);
+ objRef.current = null;
+ setObjectUrl(undefined);
+ }
+ }, [query?.data]);
+
+ useEffect(() => {
+ return () => {
+ if (objRef.current) URL.revokeObjectURL(objRef.current);
+ };
+ }, []);
+
+ const src = useMemo(() => {
+ if (isUploaded && objectUrl) return objectUrl;
+ if (!selected) return fallbackUrl;
+ return getSoundFileURL(selected) ?? fallbackUrl;
+ }, [isUploaded, objectUrl, selected, fallbackUrl]);
+
+ return {
+ src,
+ isUploaded,
+ isLoading: !!query?.isLoading,
+ error: (query?.error as Error) || undefined,
+ };
+}