import React, { useState, useEffect } from "react"; import "emoji-mart/css/emoji-mart.css"; import { useParams } from "react-router-dom"; import { Picker } from "emoji-mart"; import { toast } from "react-toastify"; import MicRecorder from "mic-recorder-to-mp3"; import { makeStyles } from "@material-ui/core/styles"; import Paper from "@material-ui/core/Paper"; import InputBase from "@material-ui/core/InputBase"; import CircularProgress from "@material-ui/core/CircularProgress"; import { green } from "@material-ui/core/colors"; import AttachFileIcon from "@material-ui/icons/AttachFile"; import IconButton from "@material-ui/core/IconButton"; import MoodIcon from "@material-ui/icons/Mood"; import SendIcon from "@material-ui/icons/Send"; 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 { i18n } from "../../translate/i18n"; import api from "../../services/api"; import RecordingTimer from "./RecordingTimer"; const Mp3Recorder = new MicRecorder({ bitRate: 128 }); const useStyles = makeStyles(theme => ({ newMessageBox: { background: "#eee", display: "flex", padding: "7px", alignItems: "center", borderTop: "1px solid rgba(0, 0, 0, 0.12)", }, messageInputWrapper: { padding: 6, background: "#fff", display: "flex", borderRadius: 20, flex: 1, }, messageInput: { paddingLeft: 10, flex: 1, border: "none", }, sendMessageIcons: { color: "grey", }, uploadInput: { display: "none", }, viewMediaInputWrapper: { display: "flex", padding: "10px 13px", position: "relative", justifyContent: "space-between", alignItems: "center", backgroundColor: "#eee", borderTop: "1px solid rgba(0, 0, 0, 0.12)", }, emojiBox: { position: "absolute", bottom: 63, width: 40, borderTop: "1px solid #e8e8e8", }, circleLoading: { color: green[500], opacity: "70%", position: "absolute", top: "20%", left: "50%", // marginTop: 8, // marginBottom: 6, marginLeft: -12, }, audioLoading: { color: green[500], opacity: "70%", }, recorderWrapper: { display: "flex", alignItems: "center", alignContent: "middle", }, cancelAudioIcon: { color: "red", }, sendAudioIcon: { color: "green", }, })); const MessageInput = ({ ticketStatus }) => { const classes = useStyles(); const { ticketId } = useParams(); const username = localStorage.getItem("username"); const mediaInitialState = { preview: "", raw: "", name: "" }; const [media, setMedia] = useState(mediaInitialState); const [inputMessage, setInputMessage] = useState(""); const [showEmoji, setShowEmoji] = useState(false); const [loading, setLoading] = useState(false); const [recording, setRecording] = useState(false); useEffect(() => { return () => { setInputMessage(""); setShowEmoji(false); setMedia({}); }; }, [ticketId]); const handleChangeInput = e => { setInputMessage(e.target.value); }; const handleAddEmoji = e => { let emoji = e.native; setInputMessage(prevState => prevState + emoji); }; const handleChangeMedia = e => { if (e.target.files.length) { setMedia({ preview: URL.createObjectURL(e.target.files[0]), raw: e.target.files[0], name: e.target.files[0].name, }); } }; const handleInputPaste = e => { if (e.clipboardData.files[0]) { setMedia({ preview: URL.createObjectURL(e.clipboardData.files[0]), raw: e.clipboardData.files[0], name: e.clipboardData.files[0].name, }); } }; const handleUploadMedia = async e => { setLoading(true); e.preventDefault(); const formData = new FormData(); formData.append("media", media.raw); formData.append("fromMe", true); formData.append("body", media.name); try { await api.post(`/messages/${ticketId}`, formData); } catch (err) { const errorMsg = err.response?.data?.error; if (errorMsg) { if (i18n.exists(`backendErrors.${errorMsg}`)) { toast.error(i18n.t(`backendErrors.${errorMsg}`)); } else { toast.error(err.response.data.error); } } else { toast.error("Unknown error"); } } setLoading(false); setMedia(mediaInitialState); }; const handleSendMessage = async () => { if (inputMessage.trim() === "") return; setLoading(true); const message = { read: 1, fromMe: true, mediaUrl: "", body: `${username}: ${inputMessage.trim()}`, }; try { await api.post(`/messages/${ticketId}`, message); } catch (err) { const errorMsg = err.response?.data?.error; if (errorMsg) { if (i18n.exists(`backendErrors.${errorMsg}`)) { toast.error(i18n.t(`backendErrors.${errorMsg}`)); } else { toast.error(err.response.data.error); } } else { toast.error("Unknown error"); } } setInputMessage(""); setShowEmoji(false); setLoading(false); }; const handleStartRecording = async () => { setLoading(true); try { await navigator.mediaDevices.getUserMedia({ audio: true }); await Mp3Recorder.start(); setRecording(true); setLoading(false); } catch (err) { console.log(err); setLoading(false); } }; const handleUploadAudio = async () => { setLoading(true); try { const [, blob] = await Mp3Recorder.stop().getMp3(); if (blob.size < 10000) { setLoading(false); setRecording(false); return; } const formData = new FormData(); const filename = `${new Date().getTime()}.mp3`; formData.append("media", blob, filename); formData.append("body", filename); formData.append("fromMe", true); await api.post(`/messages/${ticketId}`, formData); } catch (err) { const errorMsg = err.response?.data?.error; if (errorMsg) { if (i18n.exists(`backendErrors.${errorMsg}`)) { toast.error(i18n.t(`backendErrors.${errorMsg}`)); } else { toast.error(err.response.data.error); } } else { toast.error("Unknown error"); } } setRecording(false); setLoading(false); }; const handleCancelAudio = async () => { try { await Mp3Recorder.stop().getMp3(); setRecording(false); } catch (err) { console.log(err); } }; if (media.preview) return ( setMedia(mediaInitialState)} > {loading ? (
) : ( {media.name} {/* */} )}
); else { return ( setShowEmoji(prevState => !prevState)} > {showEmoji ? (
) : null}
input && input.focus()} className={classes.messageInput} placeholder={ ticketStatus === "open" ? i18n.t("messagesInput.placeholderOpen") : i18n.t("messagesInput.placeholderClosed") } multiline rowsMax={5} value={inputMessage} onChange={handleChangeInput} disabled={recording || loading || ticketStatus !== "open"} onPaste={e => { ticketStatus === "open" && handleInputPaste(e); }} onKeyPress={e => { if (loading || e.shiftKey) return; else if (e.key === "Enter") { handleSendMessage(); } }} />
{inputMessage ? ( ) : recording ? (
{loading ? (
) : ( )}
) : ( )}
); } }; export default MessageInput;