From 1ffad51503fc71ef97f318a7258120c4a0050189 Mon Sep 17 00:00:00 2001 From: Toba Ojo Date: Mon, 20 Oct 2025 16:17:37 +0100 Subject: [PATCH 1/2] fixed feature to upload sound files --- src/components/SettingForms/Sound/SoundSettingsFields.tsx | 2 +- src/components/SettingForms/Sound/SoundUpload.tsx | 6 ++++++ src/hooks/useSightingFeed.ts | 6 +++++- src/types/types.ts | 1 + src/utils/utils.ts | 4 ++++ 5 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/components/SettingForms/Sound/SoundSettingsFields.tsx b/src/components/SettingForms/Sound/SoundSettingsFields.tsx index 0c08b0b..99a8efa 100644 --- a/src/components/SettingForms/Sound/SoundSettingsFields.tsx +++ b/src/components/SettingForms/Sound/SoundSettingsFields.tsx @@ -31,7 +31,7 @@ const SoundSettingsFields = () => { NPEDsoundVolume: state.NPEDsoundVolume, hotlistSoundVolume: state.hotlistSoundVolume, }; - + console.log(updatedValues); dispatch({ type: "UPDATE", payload: updatedValues }); const result = await mutation.mutateAsync({ operation: "INSERT", diff --git a/src/components/SettingForms/Sound/SoundUpload.tsx b/src/components/SettingForms/Sound/SoundUpload.tsx index 17f28eb..7b095ba 100644 --- a/src/components/SettingForms/Sound/SoundUpload.tsx +++ b/src/components/SettingForms/Sound/SoundUpload.tsx @@ -9,6 +9,8 @@ const SoundUpload = () => { const initialValues: SoundUploadValue = { name: "", soundFile: null, + soundFileName: "", + soundUrl: "", }; const handleSubmit = (values: SoundUploadValue) => { @@ -16,6 +18,7 @@ const SoundUpload = () => { toast.warning("Please select an audio file"); } else { dispatch({ type: "ADD", payload: values }); + toast.success("Sound file upload successfully"); } }; @@ -36,7 +39,10 @@ const SoundUpload = () => { className="mt-4 w-full flex flex-col items-center justify-center rounded-2xl border border-slate-800 bg-slate-900/40 p-10 text-center file:px-3 file:border file:border-gray-500 file:rounded-lg file:bg-blue-800 file:mr-5" onChange={(e) => { if (e.target?.files && e.target?.files[0]?.type === "audio/mpeg") { + const url = URL.createObjectURL(e.target.files[0]); + setFieldValue("soundUrl", url); setFieldValue("name", e.target.files[0].name); + setFieldValue("soundFileName", e.target.files[0].name); setFieldValue("soundFile", e.target.files[0]); } else { setFieldError("soundFile", "Not an mp3 file"); diff --git a/src/hooks/useSightingFeed.ts b/src/hooks/useSightingFeed.ts index d9a386d..8a771f0 100644 --- a/src/hooks/useSightingFeed.ts +++ b/src/hooks/useSightingFeed.ts @@ -43,8 +43,12 @@ export function useSightingFeed(url: string | undefined) { }, [audioArmed, latestRef]); const soundSrc = useMemo(() => { + if (state?.sightingSound?.includes(".mp3")) { + const file = state.soundOptions?.find((item) => item.name === state.sightingSound); + return file?.soundUrl; + } return getSoundFileURL(state?.sightingSound) ?? switchSound; - }, [state.sightingSound]); + }, [state.sightingSound, state.soundOptions]); function refetchInterval(query: Query) { if (!query) return; diff --git a/src/types/types.ts b/src/types/types.ts index 37afae9..866b1e3 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -292,6 +292,7 @@ export type SoundUploadValue = { name: string; soundFileName?: string; soundFile?: File | null; + soundUrl?: string; }; export type SoundState = { diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 78c7b30..dc164e9 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -21,6 +21,10 @@ export function getSoundFileURL(name: string) { return sounds[name] ?? null; } +export const showSoundURL = (url: URL | string | undefined) => { + console.log(url); +}; + const randomChars = () => { const uppercaseAsciiStart = 65; const letterIndex = Math.floor(Math.random() * 26); From 78905b09e05ffb0d7c9d6b7ff359792211833ef0 Mon Sep 17 00:00:00 2001 From: Toba Ojo Date: Tue, 21 Oct 2025 12:52:14 +0100 Subject: [PATCH 2/2] - added framework for playing uploaded music files. need to permanently store and retreive files --- .../Sound/SoundSettingsFields.tsx | 4 ++- .../SettingForms/Sound/SoundUpload.tsx | 35 +++++++++++++++---- .../SightingsWidget/SightingWidget.tsx | 12 +++++-- .../providers/SoundContextProvider.tsx | 6 +++- src/context/reducers/SoundContextReducer.ts | 1 + src/hooks/useSightingFeed.ts | 4 +-- src/types/types.ts | 2 ++ 7 files changed, 52 insertions(+), 12 deletions(-) diff --git a/src/components/SettingForms/Sound/SoundSettingsFields.tsx b/src/components/SettingForms/Sound/SoundSettingsFields.tsx index 99a8efa..41d039e 100644 --- a/src/components/SettingForms/Sound/SoundSettingsFields.tsx +++ b/src/components/SettingForms/Sound/SoundSettingsFields.tsx @@ -30,9 +30,11 @@ const SoundSettingsFields = () => { sightingVolume: state.sightingVolume, NPEDsoundVolume: state.NPEDsoundVolume, hotlistSoundVolume: state.hotlistSoundVolume, + soundOptions: [...(state.soundOptions ?? [])], }; - console.log(updatedValues); + dispatch({ type: "UPDATE", payload: updatedValues }); + const result = await mutation.mutateAsync({ operation: "INSERT", path: "soundSettings", diff --git a/src/components/SettingForms/Sound/SoundUpload.tsx b/src/components/SettingForms/Sound/SoundUpload.tsx index 7b095ba..c30d389 100644 --- a/src/components/SettingForms/Sound/SoundUpload.tsx +++ b/src/components/SettingForms/Sound/SoundUpload.tsx @@ -3,9 +3,12 @@ import FormGroup from "../components/FormGroup"; import type { SoundUploadValue } from "../../../types/types"; import { useSoundContext } from "../../../context/SoundContext"; import { toast } from "sonner"; +import { useCameraBlackboard } from "../../../hooks/useCameraBlackboard"; const SoundUpload = () => { - const { dispatch } = useSoundContext(); + const { state, dispatch } = useSoundContext(); + const { mutation } = useCameraBlackboard(); + const initialValues: SoundUploadValue = { name: "", soundFile: null, @@ -13,14 +16,34 @@ const SoundUpload = () => { soundUrl: "", }; - const handleSubmit = (values: SoundUploadValue) => { + const handleSubmit = async (values: SoundUploadValue) => { if (!values.soundFile) { toast.warning("Please select an audio file"); - } else { - dispatch({ type: "ADD", payload: values }); - - toast.success("Sound file upload successfully"); + return; } + const alreadyExists = state?.soundOptions?.some((soundOption) => soundOption.name === values.name); + if (state.soundOptions?.includes(values) || alreadyExists) { + toast.warning("Sound already in list"); + return; + } + + const updatedValues = { + ...state, + soundOptions: [...(state.soundOptions ?? []), values], + }; + + const result = await mutation.mutateAsync({ + operation: "INSERT", + path: "soundSettings", + value: updatedValues, + }); + if (result.reason !== "OK") { + toast.error("Cannot update sound settings"); + } else { + toast.success(`${values.name} file added`); + } + + dispatch({ type: "ADD", payload: values }); }; return ( diff --git a/src/components/SightingsWidget/SightingWidget.tsx b/src/components/SightingsWidget/SightingWidget.tsx index 52317b9..4cf0de7 100644 --- a/src/components/SightingsWidget/SightingWidget.tsx +++ b/src/components/SightingsWidget/SightingWidget.tsx @@ -43,12 +43,20 @@ export default function SightingHistoryWidget({ className, title }: SightingHist 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.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.hotlistSound, state.soundOptions]); const { play: npedSound } = useSound(soundSrcNped, { volume: state.NPEDsoundVolume }); const { play: hotlistsound } = useSound(soundSrcHotlist, { volume: state.hotlistSoundVolume }); diff --git a/src/context/providers/SoundContextProvider.tsx b/src/context/providers/SoundContextProvider.tsx index 37e75ec..f534800 100644 --- a/src/context/providers/SoundContextProvider.tsx +++ b/src/context/providers/SoundContextProvider.tsx @@ -21,7 +21,11 @@ const SoundContextProvider = ({ children }: SoundContextProviderProps) => { path: "soundSettings", }); - dispatch({ type: "UPDATE", payload: result.result }); + if (!result.result || typeof result.result !== "object") { + dispatch({ type: "UPDATE", payload: state }); + } else { + dispatch({ type: "UPDATE", payload: result.result }); + } }; fetchSound(); // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/src/context/reducers/SoundContextReducer.ts b/src/context/reducers/SoundContextReducer.ts index 86cac6e..0145094 100644 --- a/src/context/reducers/SoundContextReducer.ts +++ b/src/context/reducers/SoundContextReducer.ts @@ -34,6 +34,7 @@ export function reducer(state: SoundState, action: SoundAction): SoundState { NPEDsoundVolume: action.payload.NPEDsoundVolume, sightingVolume: action.payload.sightingVolume, hotlistSoundVolume: action.payload.hotlistSoundVolume, + soundOptions: action.payload.soundOptions, }; } diff --git a/src/hooks/useSightingFeed.ts b/src/hooks/useSightingFeed.ts index 8a771f0..4c7d88e 100644 --- a/src/hooks/useSightingFeed.ts +++ b/src/hooks/useSightingFeed.ts @@ -43,9 +43,9 @@ export function useSightingFeed(url: string | undefined) { }, [audioArmed, latestRef]); const soundSrc = useMemo(() => { - if (state?.sightingSound?.includes(".mp3")) { + if (state?.sightingSound?.includes(".mp3") || state.sightingSound?.includes(".wav")) { const file = state.soundOptions?.find((item) => item.name === state.sightingSound); - return file?.soundUrl; + return file?.soundUrl ?? switchSound; } return getSoundFileURL(state?.sightingSound) ?? switchSound; }, [state.sightingSound, state.soundOptions]); diff --git a/src/types/types.ts b/src/types/types.ts index 866b1e3..72a2369 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -286,6 +286,7 @@ export type FormValues = { NPEDsound: SoundValue; hotlists: Hotlist[]; hotlistSound: SoundValue; + soundOptions?: SoundUploadValue[]; }; export type SoundUploadValue = { @@ -316,6 +317,7 @@ type UpdateAction = { NPEDsoundVolume: number; hotlistSoundVolume: number; hotlistSound: SoundValue; + soundOptions?: SoundUploadValue[]; }; };