mirror of
https://github.com/cheveguerra/whaticket-community.git
synced 2026-04-21 21:29:25 +00:00
🔈 start adding send audio support to frontend
This commit is contained in:
@@ -20,7 +20,7 @@ const app = express();
|
|||||||
|
|
||||||
const fileStorage = multer.diskStorage({
|
const fileStorage = multer.diskStorage({
|
||||||
destination: (req, file, cb) => {
|
destination: (req, file, cb) => {
|
||||||
cb(null, "public");
|
cb(null, path.resolve(__dirname, "public"));
|
||||||
},
|
},
|
||||||
filename: (req, file, cb) => {
|
filename: (req, file, cb) => {
|
||||||
cb(null, new Date().getTime() + "-" + file.originalname.replace(/\s/g, ""));
|
cb(null, new Date().getTime() + "-" + file.originalname.replace(/\s/g, ""));
|
||||||
@@ -40,9 +40,10 @@ app.use("/auth", AuthRoutes);
|
|||||||
app.use(async (err, req, res, next) => {
|
app.use(async (err, req, res, next) => {
|
||||||
if (process.env.NODE_ENV === "development") {
|
if (process.env.NODE_ENV === "development") {
|
||||||
const errors = await new Youch(err, req).toJSON();
|
const errors = await new Youch(err, req).toJSON();
|
||||||
|
console.log(err);
|
||||||
return res.status(500).json(errors);
|
return res.status(500).json(errors);
|
||||||
}
|
}
|
||||||
|
console.log(err);
|
||||||
return res.status(500).json({ error: "Internal server error" });
|
return res.status(500).json({ error: "Internal server error" });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
BIN
backend/src/public/1594126363126.ogg
Normal file
BIN
backend/src/public/1594126363126.ogg
Normal file
Binary file not shown.
23
backend/src/public/1594127076117-deployeconowhats.txt
Normal file
23
backend/src/public/1594127076117-deployeconowhats.txt
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
--- vm produção
|
||||||
|
|
||||||
|
MariaDB: root/nodecomplete
|
||||||
|
MariaDB: botter / 103economicros
|
||||||
|
dbName: econo_whatsbot
|
||||||
|
|
||||||
|
Libs necessárias para o Puppter no linux:
|
||||||
|
sudo apt-get install -y libgbm-dev wget unzip fontconfig locales gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils
|
||||||
|
|
||||||
|
|
||||||
|
-- configuração wsl2
|
||||||
|
|
||||||
|
https://docs.microsoft.com/pt-br/windows/wsl/wsl2-kernel
|
||||||
|
|
||||||
|
wsl --set-default-version 2
|
||||||
|
|
||||||
|
docker run --name whats_database -e MYSQL_ROOT_PASSWORD=103economicros --restart always -p 3306:3306 -d mariadb:latest
|
||||||
|
docker exec -it whats_database bash
|
||||||
|
|
||||||
|
CREATE DATABASE econo_whatsbot;
|
||||||
|
ALTER DATABASE econo_whatsbot CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
|
||||||
|
CREATE USER 'botter'@'%' IDENTIFIED BY 'botter';
|
||||||
|
GRANT ALL PRIVILEGES ON econo_whatsbot.* TO 'botter'@'%';
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
backend/src/public/1594127591213-1594126363126.ogg
Normal file
BIN
backend/src/public/1594127591213-1594126363126.ogg
Normal file
Binary file not shown.
BIN
backend/src/public/1594127894843-Untitled1.mp3
Normal file
BIN
backend/src/public/1594127894843-Untitled1.mp3
Normal file
Binary file not shown.
BIN
backend/src/public/1594128268424-testeeeeee.mp3
Normal file
BIN
backend/src/public/1594128268424-testeeeeee.mp3
Normal file
Binary file not shown.
BIN
backend/src/public/1594128876147-teste2.wav
Normal file
BIN
backend/src/public/1594128876147-teste2.wav
Normal file
Binary file not shown.
Binary file not shown.
@@ -12,6 +12,7 @@
|
|||||||
"date-fns": "^2.14.0",
|
"date-fns": "^2.14.0",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
"emoji-mart": "^3.0.0",
|
"emoji-mart": "^3.0.0",
|
||||||
|
"mic-recorder-to-mp3": "^2.2.1",
|
||||||
"qrcode.react": "^1.0.0",
|
"qrcode.react": "^1.0.0",
|
||||||
"react": "^16.13.1",
|
"react": "^16.13.1",
|
||||||
"react-dom": "^16.13.1",
|
"react-dom": "^16.13.1",
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ const ContactsList = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!("Notification" in window)) {
|
if (!("Notification" in window)) {
|
||||||
console.log("Esse navegador não suporte notificações");
|
console.log("This browser doesn't support notifications");
|
||||||
} else {
|
} else {
|
||||||
Notification.requestPermission();
|
Notification.requestPermission();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,27 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { useParams } from "react-router-dom";
|
|
||||||
import api from "../../../../util/api";
|
|
||||||
import "emoji-mart/css/emoji-mart.css";
|
import "emoji-mart/css/emoji-mart.css";
|
||||||
|
import { useParams } from "react-router-dom";
|
||||||
import { Picker } from "emoji-mart";
|
import { Picker } from "emoji-mart";
|
||||||
|
import MicRecorder from "mic-recorder-to-mp3";
|
||||||
|
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import Paper from "@material-ui/core/Paper";
|
import Paper from "@material-ui/core/Paper";
|
||||||
import InputBase from "@material-ui/core/InputBase";
|
import InputBase from "@material-ui/core/InputBase";
|
||||||
import CircularProgress from "@material-ui/core/CircularProgress";
|
import CircularProgress from "@material-ui/core/CircularProgress";
|
||||||
import { green } from "@material-ui/core/colors";
|
import { green } from "@material-ui/core/colors";
|
||||||
|
|
||||||
import AttachFileIcon from "@material-ui/icons/AttachFile";
|
import AttachFileIcon from "@material-ui/icons/AttachFile";
|
||||||
import IconButton from "@material-ui/core/IconButton";
|
import IconButton from "@material-ui/core/IconButton";
|
||||||
import MoodIcon from "@material-ui/icons/Mood";
|
import MoodIcon from "@material-ui/icons/Mood";
|
||||||
import SendIcon from "@material-ui/icons/Send";
|
import SendIcon from "@material-ui/icons/Send";
|
||||||
import CancelIcon from "@material-ui/icons/Cancel";
|
import CancelIcon from "@material-ui/icons/Cancel";
|
||||||
|
import MicIcon from "@material-ui/icons/Mic";
|
||||||
|
import CheckCircleOutlineIcon from "@material-ui/icons/CheckCircleOutline";
|
||||||
|
import HighlightOffIcon from "@material-ui/icons/HighlightOff";
|
||||||
|
|
||||||
|
import api from "../../../../util/api";
|
||||||
|
import RecordingTimer from "./RecordingTimer";
|
||||||
|
|
||||||
|
const Mp3Recorder = new MicRecorder({ bitRate: 128 });
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => ({
|
const useStyles = makeStyles(theme => ({
|
||||||
newMessageBox: {
|
newMessageBox: {
|
||||||
@@ -72,6 +79,20 @@ const useStyles = makeStyles(theme => ({
|
|||||||
// marginBottom: 6,
|
// marginBottom: 6,
|
||||||
marginLeft: -12,
|
marginLeft: -12,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
recorderWrapper: {
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
alignContent: "middle",
|
||||||
|
},
|
||||||
|
|
||||||
|
cancelAudioIcon: {
|
||||||
|
color: "red",
|
||||||
|
},
|
||||||
|
|
||||||
|
sendAudioIcon: {
|
||||||
|
color: "green",
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const MessagesInput = ({ searchParam }) => {
|
const MessagesInput = ({ searchParam }) => {
|
||||||
@@ -86,6 +107,9 @@ const MessagesInput = ({ searchParam }) => {
|
|||||||
const [showEmoji, setShowEmoji] = useState(false);
|
const [showEmoji, setShowEmoji] = useState(false);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
const [recording, setRecording] = useState(false);
|
||||||
|
const [blobURL, setBlobURL] = useState("");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
setInputMessage("");
|
setInputMessage("");
|
||||||
@@ -158,6 +182,33 @@ const MessagesInput = ({ searchParam }) => {
|
|||||||
setShowEmoji(false);
|
setShowEmoji(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const startRecording = () => {
|
||||||
|
navigator.getUserMedia(
|
||||||
|
{ audio: true },
|
||||||
|
() => {
|
||||||
|
Mp3Recorder.start()
|
||||||
|
.then(() => {
|
||||||
|
setRecording(true);
|
||||||
|
})
|
||||||
|
.catch(e => console.error(e));
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
console.log("Permission Denied");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const stopRecording = () => {
|
||||||
|
Mp3Recorder.stop()
|
||||||
|
.getMp3()
|
||||||
|
.then(([buffer, blob]) => {
|
||||||
|
const blobURL = URL.createObjectURL(blob);
|
||||||
|
setBlobURL(blobURL);
|
||||||
|
setRecording(false);
|
||||||
|
})
|
||||||
|
.catch(e => console.log(e));
|
||||||
|
};
|
||||||
|
|
||||||
if (media.preview)
|
if (media.preview)
|
||||||
return (
|
return (
|
||||||
<Paper
|
<Paper
|
||||||
@@ -195,6 +246,7 @@ const MessagesInput = ({ searchParam }) => {
|
|||||||
else {
|
else {
|
||||||
return (
|
return (
|
||||||
<Paper variant="outlined" square className={classes.newMessageBox}>
|
<Paper variant="outlined" square className={classes.newMessageBox}>
|
||||||
|
<audio src={blobURL} controls="controls" />
|
||||||
<IconButton
|
<IconButton
|
||||||
aria-label="emojiPicker"
|
aria-label="emojiPicker"
|
||||||
component="span"
|
component="span"
|
||||||
@@ -231,6 +283,7 @@ const MessagesInput = ({ searchParam }) => {
|
|||||||
placeholder="Escreva uma mensagem"
|
placeholder="Escreva uma mensagem"
|
||||||
value={inputMessage}
|
value={inputMessage}
|
||||||
onChange={handleChangeInput}
|
onChange={handleChangeInput}
|
||||||
|
disabled={recording}
|
||||||
onPaste={handleInputPaste}
|
onPaste={handleInputPaste}
|
||||||
onKeyPress={e => {
|
onKeyPress={e => {
|
||||||
if (e.key === "Enter") {
|
if (e.key === "Enter") {
|
||||||
@@ -239,13 +292,42 @@ const MessagesInput = ({ searchParam }) => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{inputMessage ? (
|
||||||
<IconButton
|
<IconButton
|
||||||
aria-label="emojiPicker"
|
aria-label="sendMessage"
|
||||||
component="span"
|
component="span"
|
||||||
onClick={handleSendMessage}
|
onClick={handleSendMessage}
|
||||||
>
|
>
|
||||||
<SendIcon className={classes.sendMessageIcons} />
|
<SendIcon className={classes.sendMessageIcons} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
) : recording ? (
|
||||||
|
<div className={classes.recorderWrapper}>
|
||||||
|
<IconButton
|
||||||
|
aria-label="cancelRecording"
|
||||||
|
component="span"
|
||||||
|
fontSize="large"
|
||||||
|
onClick={e => setRecording(false)}
|
||||||
|
>
|
||||||
|
<HighlightOffIcon className={classes.cancelAudioIcon} />
|
||||||
|
</IconButton>
|
||||||
|
<RecordingTimer />
|
||||||
|
<IconButton
|
||||||
|
aria-label="sendRecordedAudio"
|
||||||
|
component="span"
|
||||||
|
onClick={stopRecording}
|
||||||
|
>
|
||||||
|
<CheckCircleOutlineIcon className={classes.sendAudioIcon} />
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<IconButton
|
||||||
|
aria-label="showRecorder"
|
||||||
|
component="span"
|
||||||
|
onClick={startRecording}
|
||||||
|
>
|
||||||
|
<MicIcon className={classes.sendMessageIcons} />
|
||||||
|
</IconButton>
|
||||||
|
)}
|
||||||
</Paper>
|
</Paper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import React, { useState, useEffect } from "react";
|
||||||
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
|
|
||||||
|
const useStyles = makeStyles(theme => ({
|
||||||
|
timerBox: {
|
||||||
|
display: "flex",
|
||||||
|
marginLeft: 10,
|
||||||
|
marginRight: 10,
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const RecordingTimer = () => {
|
||||||
|
const classes = useStyles();
|
||||||
|
const initialState = {
|
||||||
|
minutes: 0,
|
||||||
|
seconds: 0,
|
||||||
|
};
|
||||||
|
const [timer, setTimer] = useState(initialState);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const interval = setInterval(
|
||||||
|
() =>
|
||||||
|
setTimer(prevState => {
|
||||||
|
if (prevState.seconds === 59) {
|
||||||
|
return { ...prevState, minutes: prevState.minutes + 1, seconds: 0 };
|
||||||
|
}
|
||||||
|
return { ...prevState, seconds: prevState.seconds + 1 };
|
||||||
|
}),
|
||||||
|
1000
|
||||||
|
);
|
||||||
|
return () => {
|
||||||
|
clearInterval(interval);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const addZero = n => {
|
||||||
|
return n < 10 ? "0" + n : n;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes.timerBox}>
|
||||||
|
<span>{`${addZero(timer.minutes)}:${addZero(timer.seconds)}`}</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RecordingTimer;
|
||||||
11508
frontend/yarn.lock
Normal file
11508
frontend/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user