import { Mic, Square } from "lucide-react"; import { useCallback, useEffect } from "react"; import { useAudioRecorder } from "@/hooks/useAudioRecorder"; import { useInferenceStore } from "@/store/inferenceStore"; /** Compact recorder. Playback + delete live in , so this * component only captures audio. UI state is derived from BOTH the * recorder hook AND the global store so the "recorded" indicator survives * tab switches that unmount this component. */ export default function MicRecorder() { const audio = useInferenceStore((s) => s.audio); const setAudio = useInferenceStore((s) => s.setAudio); const { state, start: startInternal, stop, reset, maxDurationMs, } = useAudioRecorder(15_000); const seconds = (state.durationMs / 1000).toFixed(1); // Push a fresh recording into the global audio source as soon as it lands. useEffect(() => { if (state.blob && state.objectUrl) { setAudio({ kind: "recording", blob: state.blob, objectUrl: state.objectUrl, }); } }, [state.blob, state.objectUrl, setAudio]); // If the user picks a different audio source elsewhere, free the recorder. useEffect(() => { if (audio?.kind !== "recording" && state.blob) { reset(); } }, [audio, state.blob, reset]); // Wrap start: when the user re-records, immediately clear the previous // recording from the store so NowPlaying doesn't keep showing a stale // (and now revoked) blob URL while the new recording is in progress. const start = useCallback(async () => { if (audio?.kind === "recording") { setAudio(null); } await startInternal(); }, [audio, setAudio, startInternal]); // The "recorded" indicator is true whenever either: // • this component holds a freshly-stopped blob, OR // • the global store already holds a recording (we may have just // remounted via a tab switch and lost local state). const hasRecording = state.blob != null || audio?.kind === "recording"; return (
microphone
{state.isRecording ? ( ● rec {seconds} s ) : hasRecording ? ( ● recorded {state.blob ? `${seconds} s · ` : ""} play above ) : ( 15 s max · grants browser mic permission )}
{state.isRecording ? ( ) : ( )}
{/* Recording progress bar (only meaningful while recording) */}
{state.error && (
{state.error}
)}
); }