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) */}