148 lines
4 KiB
TypeScript
148 lines
4 KiB
TypeScript
import { useInput } from "react-admin";
|
|
import React, { useState } from "react";
|
|
import dynamic from "next/dynamic";
|
|
import MicIcon from "@material-ui/icons/Mic";
|
|
import StopIcon from "@material-ui/icons/Stop";
|
|
import Button from "@material-ui/core/Button";
|
|
import { makeStyles, useTheme } from "@material-ui/core/styles";
|
|
// import AudioPlayer from "material-ui-audio-player";
|
|
import { useStopwatch } from "react-timer-hook";
|
|
import style from "./MicInput.module.css";
|
|
// import type { ReactMicProps } from "react-mic";
|
|
|
|
const ReactMic = dynamic<any>(
|
|
() => {
|
|
throw new Error(
|
|
"MIC INPUT FEATURE IS DISABLED"
|
|
); /* return import("react-mic").then((mod) => mod.ReactMic); */
|
|
},
|
|
{ ssr: false }
|
|
);
|
|
|
|
const blobToDataUri = (blob: Blob) => {
|
|
const reader = new FileReader();
|
|
reader.readAsDataURL(blob);
|
|
return new Promise((resolve) => {
|
|
reader.onloadend = () => {
|
|
resolve(reader.result);
|
|
};
|
|
});
|
|
};
|
|
|
|
const dataUriToObj = (dataUri: string) => {
|
|
const [prefix, base64] = dataUri.split(",");
|
|
const mime = prefix.slice(5, prefix.indexOf(";"));
|
|
|
|
const result: any = {};
|
|
result[mime] = base64;
|
|
return result;
|
|
};
|
|
|
|
const blobToResult = async (blob: Blob) => {
|
|
const result = dataUriToObj((await blobToDataUri(blob)) as string);
|
|
return result;
|
|
};
|
|
|
|
const resultToDataUri = (result: Record<string, any>): string => {
|
|
if (!result || !result["audio/webm"]) return "";
|
|
const base64 = result["audio/webm"];
|
|
const r = `data:audio/webm;base64,${base64}`;
|
|
return r;
|
|
};
|
|
|
|
const MicInput = (props: any) => {
|
|
const { seconds, minutes, hours, start, reset, pause } = useStopwatch();
|
|
const theme = useTheme();
|
|
const {
|
|
field: { value, onChange },
|
|
} = useInput(props);
|
|
|
|
const [record, setRecorder] = useState({ record: false });
|
|
const decodedValue = resultToDataUri(value);
|
|
const startRecording = () => {
|
|
setRecorder({ record: true });
|
|
reset();
|
|
start();
|
|
};
|
|
|
|
const stopRecording = () => {
|
|
setRecorder({ record: false });
|
|
pause();
|
|
};
|
|
|
|
async function onData(recordedBlob: any) {
|
|
console.log({ recordedBlob });
|
|
}
|
|
|
|
async function onStop(recordedBlob: any) {
|
|
const result = await blobToResult(recordedBlob.blob);
|
|
onChange(result);
|
|
}
|
|
|
|
const isRecording = record.record;
|
|
const canPlay = !isRecording && decodedValue;
|
|
const duration = `${hours.toString().padStart(2, "0")}:${minutes
|
|
.toString()
|
|
.padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
|
|
|
|
const useStyles = makeStyles(() => ({
|
|
volumeIcon: {
|
|
display: "none",
|
|
},
|
|
mainSlider: {
|
|
display: "none",
|
|
},
|
|
}));
|
|
|
|
return (
|
|
<div className="MuiFormControl-marginDense RaFormInput-input-40">
|
|
<div className={style.content}>
|
|
<div className={style.voiceWaveWrapper}>
|
|
<ReactMic
|
|
record={record.record}
|
|
className={isRecording ? style.visible : style.hidden}
|
|
onStop={onStop}
|
|
onData={onData}
|
|
strokeColor={theme.palette.primary.main}
|
|
backgroundColor="white"
|
|
mimeType="audio/webm"
|
|
visualSetting="frequencyBars"
|
|
/>
|
|
</div>
|
|
<div>{isRecording ? <p>Recording... {duration}</p> : ""}</div>
|
|
|
|
<div className={style.buttonWrapper}>
|
|
{isRecording ? (
|
|
<Button variant="contained" color="primary" onClick={stopRecording}>
|
|
<StopIcon />
|
|
Stop
|
|
</Button>
|
|
) : (
|
|
<Button
|
|
variant="contained"
|
|
color="primary"
|
|
onClick={startRecording}
|
|
style={{ marginRight: "20px" }}
|
|
>
|
|
<MicIcon />
|
|
Record
|
|
</Button>
|
|
)}
|
|
</div>
|
|
<div className={style.playerWrapper}>
|
|
{/* canPlay && (
|
|
<AudioPlayer
|
|
elevation={0}
|
|
src={decodedValue}
|
|
variation="secondary"
|
|
volume={false}
|
|
useStyles={useStyles}
|
|
/>
|
|
) */}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default MicInput;
|