62 lines
1.4 KiB
TypeScript
62 lines
1.4 KiB
TypeScript
// islands/AsyncVoiceRecorder.ts
|
|
import { useRef, useState } from "preact/hooks";
|
|
import VoiceRecorder from "./VoiceRecorder.tsx";
|
|
import { AudioFile } from "../utils/types.ts";
|
|
|
|
export function AsyncVoiceRecorder() {
|
|
const queueRef = useRef<
|
|
{
|
|
audioFile: AudioFile;
|
|
role: string;
|
|
resolve: (value: Blob | null) => void;
|
|
}[]
|
|
>([]);
|
|
const [popup, setPopup] = useState<
|
|
{
|
|
audioFile: AudioFile;
|
|
role: string;
|
|
resolve: (value: Blob | null) => void;
|
|
} | null
|
|
>(null);
|
|
|
|
// Show the popup and return a Promise for the answer
|
|
const record = (
|
|
audioFile: AudioFile,
|
|
role: string,
|
|
): Promise<Blob | null> => {
|
|
return new Promise((resolve) => {
|
|
const req = { audioFile, role, resolve };
|
|
|
|
setPopup((current) => {
|
|
if (current) {
|
|
queueRef.current.push(req);
|
|
return current;
|
|
}
|
|
return req;
|
|
});
|
|
});
|
|
};
|
|
|
|
// Render the popup if needed
|
|
const popupRecorder = popup
|
|
? (
|
|
<VoiceRecorder
|
|
text={popup.audioFile.text}
|
|
audio_file={popup.audioFile.audio_file}
|
|
role={popup.role}
|
|
recordingCallback={(answer) => {
|
|
setPopup((current) => {
|
|
if (current) {
|
|
current.resolve(answer);
|
|
}
|
|
const next = queueRef.current.shift() ?? null;
|
|
return next;
|
|
});
|
|
}}
|
|
/>
|
|
)
|
|
: null;
|
|
|
|
return [record, popupRecorder] as const;
|
|
}
|