mirror of
https://github.com/cheveguerra/whaticket-community.git
synced 2026-04-20 20:59:16 +00:00
feat: start replying messages on frontend
This commit is contained in:
@@ -1,9 +1,10 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect, useContext } from "react";
|
||||||
import "emoji-mart/css/emoji-mart.css";
|
import "emoji-mart/css/emoji-mart.css";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import { Picker } from "emoji-mart";
|
import { Picker } from "emoji-mart";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import MicRecorder from "mic-recorder-to-mp3";
|
import MicRecorder from "mic-recorder-to-mp3";
|
||||||
|
import clsx from "clsx";
|
||||||
|
|
||||||
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";
|
||||||
@@ -15,6 +16,7 @@ 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 ClearIcon from "@material-ui/icons/Clear";
|
||||||
import MicIcon from "@material-ui/icons/Mic";
|
import MicIcon from "@material-ui/icons/Mic";
|
||||||
import CheckCircleOutlineIcon from "@material-ui/icons/CheckCircleOutline";
|
import CheckCircleOutlineIcon from "@material-ui/icons/CheckCircleOutline";
|
||||||
import HighlightOffIcon from "@material-ui/icons/HighlightOff";
|
import HighlightOffIcon from "@material-ui/icons/HighlightOff";
|
||||||
@@ -22,20 +24,30 @@ import HighlightOffIcon from "@material-ui/icons/HighlightOff";
|
|||||||
import { i18n } from "../../translate/i18n";
|
import { i18n } from "../../translate/i18n";
|
||||||
import api from "../../services/api";
|
import api from "../../services/api";
|
||||||
import RecordingTimer from "./RecordingTimer";
|
import RecordingTimer from "./RecordingTimer";
|
||||||
|
import { ReplyMessageContext } from "../../context/ReplyingMessage/ReplyingMessageContext";
|
||||||
|
|
||||||
const Mp3Recorder = new MicRecorder({ bitRate: 128 });
|
const Mp3Recorder = new MicRecorder({ bitRate: 128 });
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => ({
|
const useStyles = makeStyles(theme => ({
|
||||||
newMessageBox: {
|
mainWrapper: {
|
||||||
background: "#eee",
|
background: "#eee",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
padding: "7px",
|
flexDirection: "column",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
borderTop: "1px solid rgba(0, 0, 0, 0.12)",
|
borderTop: "1px solid rgba(0, 0, 0, 0.12)",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
newMessageBox: {
|
||||||
|
background: "#eee",
|
||||||
|
width: "100%",
|
||||||
|
display: "flex",
|
||||||
|
padding: "7px",
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
|
||||||
messageInputWrapper: {
|
messageInputWrapper: {
|
||||||
padding: 6,
|
padding: 6,
|
||||||
|
marginRight: 7,
|
||||||
background: "#fff",
|
background: "#fff",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
borderRadius: 20,
|
borderRadius: 20,
|
||||||
@@ -79,8 +91,6 @@ const useStyles = makeStyles(theme => ({
|
|||||||
position: "absolute",
|
position: "absolute",
|
||||||
top: "20%",
|
top: "20%",
|
||||||
left: "50%",
|
left: "50%",
|
||||||
// marginTop: 8,
|
|
||||||
// marginBottom: 6,
|
|
||||||
marginLeft: -12,
|
marginLeft: -12,
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -102,6 +112,62 @@ const useStyles = makeStyles(theme => ({
|
|||||||
sendAudioIcon: {
|
sendAudioIcon: {
|
||||||
color: "green",
|
color: "green",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
quotedMsgWrapper: {
|
||||||
|
display: "flex",
|
||||||
|
width: "100%",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
paddingTop: 8,
|
||||||
|
paddingLeft: 73,
|
||||||
|
paddingRight: 7,
|
||||||
|
},
|
||||||
|
|
||||||
|
quotedContainerRight: {
|
||||||
|
flex: 1,
|
||||||
|
marginRight: 5,
|
||||||
|
overflowY: "hidden",
|
||||||
|
backgroundColor: "rgba(0, 0, 0, 0.05)",
|
||||||
|
borderRadius: "7.5px",
|
||||||
|
display: "flex",
|
||||||
|
position: "relative",
|
||||||
|
},
|
||||||
|
|
||||||
|
quotedMsgRight: {
|
||||||
|
padding: 10,
|
||||||
|
maxWidth: 300,
|
||||||
|
height: "auto",
|
||||||
|
whiteSpace: "pre-wrap",
|
||||||
|
},
|
||||||
|
|
||||||
|
quotedSideRight: {
|
||||||
|
flex: "none",
|
||||||
|
width: "4px",
|
||||||
|
backgroundColor: "#35cd96",
|
||||||
|
},
|
||||||
|
|
||||||
|
quotedContainerLeft: {
|
||||||
|
overflow: "hidden",
|
||||||
|
backgroundColor: "rgba(0, 0, 0, 0.05)",
|
||||||
|
borderRadius: "7.5px",
|
||||||
|
display: "flex",
|
||||||
|
position: "relative",
|
||||||
|
},
|
||||||
|
|
||||||
|
quotedMsg: {
|
||||||
|
padding: 10,
|
||||||
|
maxWidth: 300,
|
||||||
|
height: "auto",
|
||||||
|
display: "block",
|
||||||
|
whiteSpace: "pre-wrap",
|
||||||
|
overflow: "hidden",
|
||||||
|
},
|
||||||
|
|
||||||
|
quotedSideLeft: {
|
||||||
|
flex: "none",
|
||||||
|
width: "4px",
|
||||||
|
backgroundColor: "#6bcbef",
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const MessageInput = ({ ticketStatus }) => {
|
const MessageInput = ({ ticketStatus }) => {
|
||||||
@@ -114,6 +180,9 @@ const MessageInput = ({ ticketStatus }) => {
|
|||||||
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 [recording, setRecording] = useState(false);
|
||||||
|
const { setReplyingMessage, replyingMessage } = useContext(
|
||||||
|
ReplyMessageContext
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
@@ -263,6 +332,40 @@ const MessageInput = ({ ticketStatus }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const renderQuotedMessage = message => {
|
||||||
|
return (
|
||||||
|
<div className={classes.quotedMsgWrapper}>
|
||||||
|
<div
|
||||||
|
className={clsx(classes.quotedContainerLeft, {
|
||||||
|
[classes.quotedContainerRight]: message.fromMe,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className={clsx(classes.quotedSideLeft, {
|
||||||
|
[classes.quotedSideRight]: message.quotedMsg?.fromMe,
|
||||||
|
})}
|
||||||
|
></span>
|
||||||
|
<div className={classes.quotedMsg}>
|
||||||
|
{!message.fromMe && (
|
||||||
|
<span className={classes.messageContactName}>
|
||||||
|
{message.contact?.name}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{message.body}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<IconButton
|
||||||
|
aria-label="showRecorder"
|
||||||
|
component="span"
|
||||||
|
disabled={loading || ticketStatus !== "open"}
|
||||||
|
onClick={() => setReplyingMessage({})}
|
||||||
|
>
|
||||||
|
<ClearIcon className={classes.sendMessageIcons} />
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
if (medias.length > 0)
|
if (medias.length > 0)
|
||||||
return (
|
return (
|
||||||
<Paper elevation={0} square className={classes.viewMediaInputWrapper}>
|
<Paper elevation={0} square className={classes.viewMediaInputWrapper}>
|
||||||
@@ -296,115 +399,118 @@ const MessageInput = ({ ticketStatus }) => {
|
|||||||
);
|
);
|
||||||
else {
|
else {
|
||||||
return (
|
return (
|
||||||
<Paper square elevation={0} className={classes.newMessageBox}>
|
<Paper square elevation={0} className={classes.mainWrapper}>
|
||||||
<IconButton
|
{replyingMessage.id && renderQuotedMessage(replyingMessage)}
|
||||||
aria-label="emojiPicker"
|
<div className={classes.newMessageBox}>
|
||||||
component="span"
|
|
||||||
disabled={loading || recording || ticketStatus !== "open"}
|
|
||||||
onClick={e => setShowEmoji(prevState => !prevState)}
|
|
||||||
>
|
|
||||||
<MoodIcon className={classes.sendMessageIcons} />
|
|
||||||
</IconButton>
|
|
||||||
{showEmoji ? (
|
|
||||||
<div className={classes.emojiBox}>
|
|
||||||
<Picker
|
|
||||||
perLine={16}
|
|
||||||
showPreview={false}
|
|
||||||
showSkinTones={false}
|
|
||||||
onSelect={handleAddEmoji}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
<input
|
|
||||||
multiple
|
|
||||||
type="file"
|
|
||||||
id="upload-button"
|
|
||||||
disabled={loading || recording || ticketStatus !== "open"}
|
|
||||||
className={classes.uploadInput}
|
|
||||||
onChange={handleChangeMedias}
|
|
||||||
/>
|
|
||||||
<label htmlFor="upload-button">
|
|
||||||
<IconButton
|
<IconButton
|
||||||
aria-label="upload"
|
aria-label="emojiPicker"
|
||||||
component="span"
|
component="span"
|
||||||
disabled={loading || recording || ticketStatus !== "open"}
|
disabled={loading || recording || ticketStatus !== "open"}
|
||||||
|
onClick={e => setShowEmoji(prevState => !prevState)}
|
||||||
>
|
>
|
||||||
<AttachFileIcon className={classes.sendMessageIcons} />
|
<MoodIcon className={classes.sendMessageIcons} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</label>
|
{showEmoji ? (
|
||||||
<div className={classes.messageInputWrapper}>
|
<div className={classes.emojiBox}>
|
||||||
<InputBase
|
<Picker
|
||||||
inputRef={input => input && input.focus()}
|
perLine={16}
|
||||||
className={classes.messageInput}
|
showPreview={false}
|
||||||
placeholder={
|
showSkinTones={false}
|
||||||
ticketStatus === "open"
|
onSelect={handleAddEmoji}
|
||||||
? i18n.t("messagesInput.placeholderOpen")
|
/>
|
||||||
: i18n.t("messagesInput.placeholderClosed")
|
</div>
|
||||||
}
|
) : null}
|
||||||
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();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{inputMessage ? (
|
|
||||||
<IconButton
|
|
||||||
aria-label="sendMessage"
|
|
||||||
component="span"
|
|
||||||
onClick={handleSendMessage}
|
|
||||||
disabled={loading}
|
|
||||||
>
|
|
||||||
<SendIcon className={classes.sendMessageIcons} />
|
|
||||||
</IconButton>
|
|
||||||
) : recording ? (
|
|
||||||
<div className={classes.recorderWrapper}>
|
|
||||||
<IconButton
|
|
||||||
aria-label="cancelRecording"
|
|
||||||
component="span"
|
|
||||||
fontSize="large"
|
|
||||||
disabled={loading}
|
|
||||||
onClick={handleCancelAudio}
|
|
||||||
>
|
|
||||||
<HighlightOffIcon className={classes.cancelAudioIcon} />
|
|
||||||
</IconButton>
|
|
||||||
{loading ? (
|
|
||||||
<div>
|
|
||||||
<CircularProgress className={classes.audioLoading} />
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<RecordingTimer />
|
|
||||||
)}
|
|
||||||
|
|
||||||
|
<input
|
||||||
|
multiple
|
||||||
|
type="file"
|
||||||
|
id="upload-button"
|
||||||
|
disabled={loading || recording || ticketStatus !== "open"}
|
||||||
|
className={classes.uploadInput}
|
||||||
|
onChange={handleChangeMedias}
|
||||||
|
/>
|
||||||
|
<label htmlFor="upload-button">
|
||||||
<IconButton
|
<IconButton
|
||||||
aria-label="sendRecordedAudio"
|
aria-label="upload"
|
||||||
component="span"
|
component="span"
|
||||||
onClick={handleUploadAudio}
|
disabled={loading || recording || ticketStatus !== "open"}
|
||||||
|
>
|
||||||
|
<AttachFileIcon className={classes.sendMessageIcons} />
|
||||||
|
</IconButton>
|
||||||
|
</label>
|
||||||
|
<div className={classes.messageInputWrapper}>
|
||||||
|
<InputBase
|
||||||
|
inputRef={input => 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();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{inputMessage ? (
|
||||||
|
<IconButton
|
||||||
|
aria-label="sendMessage"
|
||||||
|
component="span"
|
||||||
|
onClick={handleSendMessage}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
>
|
>
|
||||||
<CheckCircleOutlineIcon className={classes.sendAudioIcon} />
|
<SendIcon className={classes.sendMessageIcons} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</div>
|
) : recording ? (
|
||||||
) : (
|
<div className={classes.recorderWrapper}>
|
||||||
<IconButton
|
<IconButton
|
||||||
aria-label="showRecorder"
|
aria-label="cancelRecording"
|
||||||
component="span"
|
component="span"
|
||||||
disabled={loading || ticketStatus !== "open"}
|
fontSize="large"
|
||||||
onClick={handleStartRecording}
|
disabled={loading}
|
||||||
>
|
onClick={handleCancelAudio}
|
||||||
<MicIcon className={classes.sendMessageIcons} />
|
>
|
||||||
</IconButton>
|
<HighlightOffIcon className={classes.cancelAudioIcon} />
|
||||||
)}
|
</IconButton>
|
||||||
|
{loading ? (
|
||||||
|
<div>
|
||||||
|
<CircularProgress className={classes.audioLoading} />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<RecordingTimer />
|
||||||
|
)}
|
||||||
|
|
||||||
|
<IconButton
|
||||||
|
aria-label="sendRecordedAudio"
|
||||||
|
component="span"
|
||||||
|
onClick={handleUploadAudio}
|
||||||
|
disabled={loading}
|
||||||
|
>
|
||||||
|
<CheckCircleOutlineIcon className={classes.sendAudioIcon} />
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<IconButton
|
||||||
|
aria-label="showRecorder"
|
||||||
|
component="span"
|
||||||
|
disabled={loading || ticketStatus !== "open"}
|
||||||
|
onClick={handleStartRecording}
|
||||||
|
>
|
||||||
|
<MicIcon className={classes.sendMessageIcons} />
|
||||||
|
</IconButton>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</Paper>
|
</Paper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState, useContext } from "react";
|
||||||
|
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
|
|
||||||
@@ -8,13 +8,15 @@ import { i18n } from "../../translate/i18n";
|
|||||||
import api from "../../services/api";
|
import api from "../../services/api";
|
||||||
import ConfirmationModal from "../ConfirmationModal";
|
import ConfirmationModal from "../ConfirmationModal";
|
||||||
import { Menu } from "@material-ui/core";
|
import { Menu } from "@material-ui/core";
|
||||||
|
import { ReplyMessageContext } from "../../context/ReplyingMessage/ReplyingMessageContext";
|
||||||
|
|
||||||
const MessageOptionsMenu = ({ messageId, menuOpen, handleClose, anchorEl }) => {
|
const MessageOptionsMenu = ({ message, menuOpen, handleClose, anchorEl }) => {
|
||||||
|
const { setReplyingMessage } = useContext(ReplyMessageContext);
|
||||||
const [confirmationOpen, setConfirmationOpen] = useState(false);
|
const [confirmationOpen, setConfirmationOpen] = useState(false);
|
||||||
|
|
||||||
const handleDeleteMessage = async () => {
|
const handleDeleteMessage = async () => {
|
||||||
try {
|
try {
|
||||||
await api.delete(`/messages/${messageId}`);
|
await api.delete(`/messages/${message.id}`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const errorMsg = err.response?.data?.error;
|
const errorMsg = err.response?.data?.error;
|
||||||
if (errorMsg) {
|
if (errorMsg) {
|
||||||
@@ -29,6 +31,11 @@ const MessageOptionsMenu = ({ messageId, menuOpen, handleClose, anchorEl }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const hanldeReplyMessage = () => {
|
||||||
|
setReplyingMessage(message);
|
||||||
|
handleClose();
|
||||||
|
};
|
||||||
|
|
||||||
const handleOpenConfirmationModal = e => {
|
const handleOpenConfirmationModal = e => {
|
||||||
setConfirmationOpen(true);
|
setConfirmationOpen(true);
|
||||||
handleClose();
|
handleClose();
|
||||||
@@ -61,7 +68,9 @@ const MessageOptionsMenu = ({ messageId, menuOpen, handleClose, anchorEl }) => {
|
|||||||
<MenuItem onClick={handleOpenConfirmationModal}>
|
<MenuItem onClick={handleOpenConfirmationModal}>
|
||||||
{i18n.t("messageOptionsMenu.delete")}
|
{i18n.t("messageOptionsMenu.delete")}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem disabled> {i18n.t("messageOptionsMenu.reply")}</MenuItem>
|
<MenuItem onClick={hanldeReplyMessage}>
|
||||||
|
{i18n.t("messageOptionsMenu.reply")}
|
||||||
|
</MenuItem>
|
||||||
</Menu>
|
</Menu>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -295,7 +295,7 @@ const reducer = (state, action) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const MessagesList = ({ ticketId, isGroup }) => {
|
const MessagesList = ({ ticketId, isGroup, setReplyingMessage }) => {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
||||||
const [messagesList, dispatch] = useReducer(reducer, []);
|
const [messagesList, dispatch] = useReducer(reducer, []);
|
||||||
@@ -304,7 +304,7 @@ const MessagesList = ({ ticketId, isGroup }) => {
|
|||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const lastMessageRef = useRef();
|
const lastMessageRef = useRef();
|
||||||
|
|
||||||
const [selectedMessageId, setSelectedMessageId] = useState(null);
|
const [selectedMessage, setSelectedMessage] = useState({});
|
||||||
const [anchorEl, setAnchorEl] = useState(null);
|
const [anchorEl, setAnchorEl] = useState(null);
|
||||||
const messageOptionsMenuOpen = Boolean(anchorEl);
|
const messageOptionsMenuOpen = Boolean(anchorEl);
|
||||||
const currentTicketId = useRef(ticketId);
|
const currentTicketId = useRef(ticketId);
|
||||||
@@ -402,9 +402,9 @@ const MessagesList = ({ ticketId, isGroup }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOpenMessageOptionsMenu = (e, messageId) => {
|
const handleOpenMessageOptionsMenu = (e, message) => {
|
||||||
setAnchorEl(e.currentTarget);
|
setAnchorEl(e.currentTarget);
|
||||||
setSelectedMessageId(messageId);
|
setSelectedMessage(message);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCloseMessageOptionsMenu = e => {
|
const handleCloseMessageOptionsMenu = e => {
|
||||||
@@ -581,7 +581,7 @@ const MessagesList = ({ ticketId, isGroup }) => {
|
|||||||
id="messageActionsButton"
|
id="messageActionsButton"
|
||||||
disabled={message.isDeleted}
|
disabled={message.isDeleted}
|
||||||
className={classes.messageActionsButton}
|
className={classes.messageActionsButton}
|
||||||
onClick={e => handleOpenMessageOptionsMenu(e, message.id)}
|
onClick={e => handleOpenMessageOptionsMenu(e, message)}
|
||||||
>
|
>
|
||||||
<ExpandMore />
|
<ExpandMore />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@@ -619,7 +619,7 @@ const MessagesList = ({ ticketId, isGroup }) => {
|
|||||||
return (
|
return (
|
||||||
<div className={classes.messagesListWrapper}>
|
<div className={classes.messagesListWrapper}>
|
||||||
<MessageOptionsMenu
|
<MessageOptionsMenu
|
||||||
messageId={selectedMessageId}
|
message={selectedMessage}
|
||||||
anchorEl={anchorEl}
|
anchorEl={anchorEl}
|
||||||
menuOpen={messageOptionsMenuOpen}
|
menuOpen={messageOptionsMenuOpen}
|
||||||
handleClose={handleCloseMessageOptionsMenu}
|
handleClose={handleCloseMessageOptionsMenu}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import TicketActionButtons from "../TicketActionButtons";
|
|||||||
import MessagesList from "../MessagesList";
|
import MessagesList from "../MessagesList";
|
||||||
import api from "../../services/api";
|
import api from "../../services/api";
|
||||||
import { i18n } from "../../translate/i18n";
|
import { i18n } from "../../translate/i18n";
|
||||||
|
import { ReplyMessageProvider } from "../../context/ReplyingMessage/ReplyingMessageContext";
|
||||||
|
|
||||||
const drawerWidth = 320;
|
const drawerWidth = 320;
|
||||||
|
|
||||||
@@ -151,11 +152,13 @@ const Ticket = () => {
|
|||||||
/>
|
/>
|
||||||
<TicketActionButtons ticket={ticket} />
|
<TicketActionButtons ticket={ticket} />
|
||||||
</TicketHeader>
|
</TicketHeader>
|
||||||
<MessagesList
|
<ReplyMessageProvider>
|
||||||
ticketId={ticketId}
|
<MessagesList
|
||||||
isGroup={ticket.isGroup}
|
ticketId={ticketId}
|
||||||
></MessagesList>
|
isGroup={ticket.isGroup}
|
||||||
<MessageInput ticketStatus={ticket.status} />
|
></MessagesList>
|
||||||
|
<MessageInput ticketStatus={ticket.status} />
|
||||||
|
</ReplyMessageProvider>
|
||||||
</Paper>
|
</Paper>
|
||||||
<ContactDrawer
|
<ContactDrawer
|
||||||
open={drawerOpen}
|
open={drawerOpen}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import React, { useState, createContext } from "react";
|
||||||
|
|
||||||
|
const ReplyMessageContext = createContext();
|
||||||
|
|
||||||
|
const ReplyMessageProvider = ({ children }) => {
|
||||||
|
const [replyingMessage, setReplyingMessage] = useState({});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ReplyMessageContext.Provider
|
||||||
|
value={{ replyingMessage, setReplyingMessage }}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</ReplyMessageContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { ReplyMessageContext, ReplyMessageProvider };
|
||||||
Reference in New Issue
Block a user