From 907555cb0dcb9597ff6015c882e711bb1dafc69c Mon Sep 17 00:00:00 2001 From: Toba Ojo Date: Tue, 28 Oct 2025 09:54:29 +0000 Subject: [PATCH] - storing changes for now --- .../Sound/SoundSettingsFields.tsx | 35 +++---------------- src/hooks/useFileUpload.ts | 8 ++--- src/hooks/useSightingFeed.ts | 29 ++++++++++++--- src/utils/cacheSound.ts | 16 +++++++++ 4 files changed, 47 insertions(+), 41 deletions(-) create mode 100644 src/utils/cacheSound.ts diff --git a/src/components/SettingForms/Sound/SoundSettingsFields.tsx b/src/components/SettingForms/Sound/SoundSettingsFields.tsx index 59437c7..539c155 100644 --- a/src/components/SettingForms/Sound/SoundSettingsFields.tsx +++ b/src/components/SettingForms/Sound/SoundSettingsFields.tsx @@ -6,15 +6,11 @@ import { useCameraBlackboard } from "../../../hooks/useCameraBlackboard"; import { toast } from "sonner"; import SliderComponent from "../../UI/Slider"; import { useFileUpload } from "../../../hooks/useFileUpload"; -import { useSound } from "react-sounds"; -import { useMemo } from "react"; -import { getSoundFileURL } from "../../../utils/utils"; const SoundSettingsFields = () => { const { state, dispatch } = useSoundContext(); const { mutation } = useCameraBlackboard(); - - const { query } = useFileUpload({ + const { query: fileQuery } = useFileUpload({ queryKey: state.sightingSound ? [state.sightingSound] : undefined, }); @@ -31,31 +27,8 @@ const SoundSettingsFields = () => { hotlistSound: state.hotlistSound ?? "notification", hotlists, }; - - const soundSrc = useMemo(() => { - if (state?.sightingSound?.includes(".mp3") || state.sightingSound?.includes(".wav")) { - const file = state.soundOptions?.find((item) => item.name === state.sightingSound); - query?.refetch(); - console.log(query?.data); - - // set state - dispatch({ type: "UPLOADEDSOUND", payload: query?.data }); - if (!query?.data) { - query?.refetch(); - return; - } - //get from state? - if (!state.uploadedSound) return "switchSound"; - const url = URL.createObjectURL(state.uploadedSound); - return url ?? "switchSound"; - } - return getSoundFileURL(state?.sightingSound) ?? "switchSound"; - }, [state.sightingSound, state.soundOptions]); - - const { play } = useSound(soundSrc); - const handletest = () => { - console.log(state.uploadedSound); - play(); + const handleSyce = () => { + fileQuery?.refetch(); }; const handleSubmit = async (values: FormValues) => { const updatedValues = { @@ -176,7 +149,7 @@ const SoundSettingsFields = () => { > Save Settings - diff --git a/src/hooks/useFileUpload.ts b/src/hooks/useFileUpload.ts index 7fbbb1f..b1da0b9 100644 --- a/src/hooks/useFileUpload.ts +++ b/src/hooks/useFileUpload.ts @@ -1,6 +1,7 @@ import { useMutation, useQuery } from "@tanstack/react-query"; import { CAM_BASE } from "../utils/config"; import { toast } from "sonner"; +import { getOrCacheBlob } from "../utils/cacheSound"; const camBase = import.meta.env.MODE !== "development" ? CAM_BASE : CAM_BASE; type UseFileUploadProps = { @@ -22,11 +23,8 @@ const uploadFile = async (file: File) => { const getUploadFiles = async ({ queryKey }: { queryKey: string[] }) => { const [, fileName] = queryKey; - const response = await fetch(`${camBase}/Mobile/${fileName}`); - if (!response.ok) { - throw new Error("Cannot reach upload file endpoint"); - } - return response.blob(); + const url = `${camBase}/Mobile/${fileName}`; + return getOrCacheBlob(url); }; export const useFileUpload = ({ queryKey }: UseFileUploadProps) => { diff --git a/src/hooks/useSightingFeed.ts b/src/hooks/useSightingFeed.ts index a3d19a8..30283f2 100644 --- a/src/hooks/useSightingFeed.ts +++ b/src/hooks/useSightingFeed.ts @@ -8,6 +8,7 @@ import { checkIsHotListHit, getNPEDCategory, getSoundFileURL } from "../utils/ut 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"; async function fetchSighting(url: string | undefined, ref: number): Promise { const res = await fetch(`${url}${ref}`, { @@ -18,12 +19,22 @@ 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); @@ -41,12 +52,20 @@ export function useSightingFeed(url: string | undefined) { }, [state.NPEDsound, state.soundOptions]); const soundSrc = useMemo(() => { - if (state?.sightingSound?.includes(".mp3") || state.sightingSound?.includes(".wav")) { - const file = state.soundOptions?.find((item) => item.name === state.sightingSound); - return file?.soundUrl ?? switchSound; + 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; - }, [state.sightingSound, state.soundOptions]); + }, [isUploaded, fileQuery?.data, state?.sightingSound]); + + useEffect(() => { + return () => { + if (objUrlRef.current) URL.revokeObjectURL(objUrlRef.current); + }; + }, []); const { play: hotlistsound } = useSound(soundSrcHotlist, { volume: state.hotlistSoundVolume }); const { play: npedSound } = useSound(soundSrcNped, { volume: state.NPEDsoundVolume }); diff --git a/src/utils/cacheSound.ts b/src/utils/cacheSound.ts new file mode 100644 index 0000000..536e321 --- /dev/null +++ b/src/utils/cacheSound.ts @@ -0,0 +1,16 @@ +export async function getOrCacheBlob(url: string) { + const cache = await caches.open("app-sounds-v1"); + const hit = await cache.match(url); + if (hit) return await hit.blob(); + + const res = await fetch(url, { cache: "no-store" }); + if (!res.ok) throw new Error(`Fetch failed: ${res.status}`); + await cache.put(url, res.clone()); + + return await res.blob(); +} + +export async function evictFromCache(url: string) { + const cache = await caches.open("app-sounds-v1"); + await cache.delete(url); +}