import { useEffect, useMemo, useReducer, useRef, useState, type ReactNode } from "react"; import { SoundContext } from "../SoundContext"; import { initialState, reducer } from "../reducers/SoundContextReducer"; import { useCameraBlackboard } from "../../hooks/useCameraBlackboard"; type SoundContextProviderProps = { children: ReactNode; }; const SoundContextProvider = ({ children }: SoundContextProviderProps) => { const audioReady = useRef(false); const [audioArmed, setAudioArmed] = useState(false); const audioCtxRef = useRef(null); const [state, dispatch] = useReducer(reducer, initialState); const { mutation } = useCameraBlackboard(); useEffect(() => { const fetchSound = async () => { const result = await mutation.mutateAsync({ operation: "VIEW", path: "soundSettings", }); dispatch({ type: "UPDATE", payload: result.result }); }; fetchSound(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); useEffect(() => { const unlock = async () => { if (!audioCtxRef.current) audioCtxRef.current = new AudioContext(); if (audioCtxRef.current.state !== "running") { try { await audioCtxRef.current.resume(); } catch { /* empty */ } } const armed = audioCtxRef.current.state === "running"; audioReady.current = audioCtxRef.current.state === "running"; setAudioArmed(armed); if (audioReady.current) { window.removeEventListener("pointerdown", unlock); window.removeEventListener("keydown", unlock); window.removeEventListener("touchstart", unlock); } }; window.addEventListener("pointerdown", unlock, { once: false }); window.addEventListener("keydown", unlock, { once: false }); window.addEventListener("touchstart", unlock, { once: false }); return () => { window.removeEventListener("pointerdown", unlock); window.removeEventListener("keydown", unlock); window.removeEventListener("touchstart", unlock); }; }, []); const value = useMemo(() => ({ state, dispatch, audioArmed }), [state, audioArmed]); return {children}; }; export default SoundContextProvider;