diff --git a/backend/src/controllers/TicketController.js b/backend/src/controllers/TicketController.js
index 8c79642..02e002e 100644
--- a/backend/src/controllers/TicketController.js
+++ b/backend/src/controllers/TicketController.js
@@ -3,11 +3,13 @@ const Sequelize = require("sequelize");
const Ticket = require("../models/Ticket");
const Contact = require("../models/Contact");
+const { getIO } = require("../libs/socket");
+
exports.index = async (req, res) => {
const { status = "" } = req.query;
let whereCondition;
- if (!status) {
+ if (!status || status === "open") {
whereCondition = ["pending", "open"];
} else {
whereCondition = [status];
@@ -51,6 +53,7 @@ exports.store = async (req, res) => {
};
exports.update = async (req, res) => {
+ const io = getIO();
const { ticketId } = req.params;
const ticket = await Ticket.findByPk(ticketId, {
@@ -84,5 +87,10 @@ exports.update = async (req, res) => {
await ticket.update(req.body);
+ io.to("notification").emit("ticket", {
+ action: "updateStatus",
+ ticket: ticket,
+ });
+
res.status(200).json(ticket);
};
diff --git a/backend/src/services/wbotMessageListener.js b/backend/src/services/wbotMessageListener.js
index 00912ad..7e4fa44 100644
--- a/backend/src/services/wbotMessageListener.js
+++ b/backend/src/services/wbotMessageListener.js
@@ -133,6 +133,7 @@ const wbotMessageListener = () => {
action: "create",
message: serializedMessage,
ticket: serializaedTicket,
+ contact: contact,
});
let chat = await msg.getChat();
diff --git a/frontend/src/components/Layout/MainDrawer.js b/frontend/src/components/Layout/MainDrawer.js
index 2e2fb10..cf101f2 100644
--- a/frontend/src/components/Layout/MainDrawer.js
+++ b/frontend/src/components/Layout/MainDrawer.js
@@ -220,7 +220,7 @@ const MainDrawer = ({ appTitle, children }) => {
- {children ? children : Dashboard
}
+ {children ? children : null}
);
diff --git a/frontend/src/pages/Chat/Chat.js b/frontend/src/pages/Chat/Chat.js
index eb6400d..b5a90da 100644
--- a/frontend/src/pages/Chat/Chat.js
+++ b/frontend/src/pages/Chat/Chat.js
@@ -4,15 +4,14 @@ import Grid from "@material-ui/core/Grid";
import Paper from "@material-ui/core/Paper";
import { makeStyles } from "@material-ui/core/styles";
-import ContactsList from "./components/ContactsList/ContactsList";
+import TicketsList from "./components/TicketsList/TicketsList";
import MessagesList from "./components/MessagesList/MessagesList";
-import MainDrawer from "../../components/Layout/MainDrawer";
const useStyles = makeStyles(theme => ({
chatContainer: {
flex: 1,
- backgroundColor: "#eee",
- // padding: 20,
+ // backgroundColor: "#eee",
+ padding: theme.spacing(4),
height: `calc(100% - 64px)`,
overflowY: "hidden",
},
@@ -48,36 +47,28 @@ const useStyles = makeStyles(theme => ({
const Chat = () => {
const classes = useStyles();
- const { contactId } = useParams();
+ const { ticketId } = useParams();
return (
-
-
-
-
-
-
-
-
-
- {contactId ? (
- <>
-
- >
- ) : (
-
- Selecione um contato para começar a conversar
-
- )}
-
-
-
-
-
+
+
+
+
+
+
+
+ {ticketId ? (
+ <>
+
+ >
+ ) : (
+
+ Selecione um contato para começar a conversar
+
+ )}
+
+
+
);
};
diff --git a/frontend/src/pages/Chat/components/ContactsList/ContactsList.js b/frontend/src/pages/Chat/components/ContactsList/ContactsList.js
deleted file mode 100644
index 129c433..0000000
--- a/frontend/src/pages/Chat/components/ContactsList/ContactsList.js
+++ /dev/null
@@ -1,378 +0,0 @@
-import React, { useState, useEffect } from "react";
-import { useHistory, useParams } from "react-router-dom";
-import api from "../../../../util/api";
-import openSocket from "socket.io-client";
-
-import { parseISO, format } from "date-fns";
-
-import profileDefaultPic from "../../../../Images/profile_default.png";
-
-import { makeStyles } from "@material-ui/core/styles";
-import { green } from "@material-ui/core/colors";
-import CircularProgress from "@material-ui/core/CircularProgress";
-import Paper from "@material-ui/core/Paper";
-import List from "@material-ui/core/List";
-import ListItem from "@material-ui/core/ListItem";
-import ListItemText from "@material-ui/core/ListItemText";
-import ListItemAvatar from "@material-ui/core/ListItemAvatar";
-import Typography from "@material-ui/core/Typography";
-import Avatar from "@material-ui/core/Avatar";
-import AddIcon from "@material-ui/icons/Add";
-import Divider from "@material-ui/core/Divider";
-import Badge from "@material-ui/core/Badge";
-import SearchIcon from "@material-ui/icons/Search";
-import InputBase from "@material-ui/core/InputBase";
-import Fab from "@material-ui/core/Fab";
-import AddContactModal from "../AddContact/AddContactModal";
-
-import ContactsHeader from "../ContactsHeader/ContactsHeader";
-
-const useStyles = makeStyles(theme => ({
- contactsWrapper: {
- display: "flex",
- height: "100%",
- flexDirection: "column",
- overflow: "hidden",
- },
-
- contactsHeader: {
- display: "flex",
- backgroundColor: "#eee",
- borderBottomLeftRadius: 0,
- borderBottomRightRadius: 0,
- borderTopRightRadius: 0,
- },
-
- settingsIcon: {
- alignSelf: "center",
- marginLeft: "auto",
- padding: 8,
- },
-
- contactsList: {
- position: "relative",
- borderTopLeftRadius: 0,
- borderTopRightRadius: 0,
- borderBottomRightRadius: 0,
- flexGrow: 1,
- overflowY: "scroll",
- "&::-webkit-scrollbar": {
- width: "8px",
- },
- "&::-webkit-scrollbar-thumb": {
- boxShadow: "inset 0 0 6px rgba(0, 0, 0, 0.3)",
- backgroundColor: "#e8e8e8",
- },
- },
- contactsSearchBox: {
- position: "relative",
- background: "#fafafa",
- padding: "10px 13px",
- },
-
- serachInputWrapper: {
- background: "#fff",
- display: "flex",
- borderRadius: 40,
- padding: 4,
- },
-
- searchIcon: {
- color: "grey",
- marginLeft: 6,
- marginRight: 6,
- alignSelf: "center",
- },
-
- contactsSearchInput: {
- flex: 1,
- border: "none",
- borderRadius: 30,
- },
-
- contactNameWrapper: {
- display: "flex",
- // display: "inline",
- },
-
- lastMessageTime: {
- marginLeft: "auto",
- },
-
- contactLastMessage: {
- paddingRight: 20,
- },
-
- newMessagesCount: {
- alignSelf: "center",
- marginRight: 8,
- marginLeft: "auto",
- },
-
- badgeStyle: {
- color: "white",
- backgroundColor: green[500],
- },
- circleLoading: {
- color: green[500],
- opacity: "70%",
- position: "absolute",
- top: 0,
- left: "50%",
- marginTop: 12,
- // marginLeft: -12,
- },
- fabButton: {
- position: "absolute",
- zIndex: 1,
- bottom: 20,
- left: 0,
- right: 0,
- margin: "0 auto",
- },
-}));
-
-const ContactsList = () => {
- const classes = useStyles();
- const token = localStorage.getItem("token");
- const { contactId } = useParams();
- const [contacts, setContacts] = useState([]);
- const [loading, setLoading] = useState();
- const [searchParam, setSearchParam] = useState("");
-
- const [modalOpen, setModalOpen] = useState(false);
-
- const history = useHistory();
-
- useEffect(() => {
- if (!("Notification" in window)) {
- console.log("This browser doesn't support notifications");
- } else {
- Notification.requestPermission();
- }
- }, []);
-
- useEffect(() => {
- setLoading(true);
- const delayDebounceFn = setTimeout(() => {
- const fetchContacts = async () => {
- try {
- const res = await api.get("/contacts", {
- params: { searchParam },
- });
- setContacts(res.data);
- setLoading(false);
- } catch (err) {
- console.log(err);
- }
- };
- fetchContacts();
- }, 1000);
- return () => clearTimeout(delayDebounceFn);
- }, [searchParam, token]);
-
- useEffect(() => {
- const socket = openSocket(process.env.REACT_APP_BACKEND_URL);
-
- socket.emit("joinNotification");
-
- socket.on("contact", data => {
- if (data.action === "updateUnread") {
- resetUnreadMessages(data.contactId);
- }
- });
-
- socket.on("appMessage", data => {
- if (data.action === "create") {
- updateUnreadMessagesCount(data);
- if (
- contactId &&
- data.message.contactId === +contactId &&
- document.visibilityState === "visible"
- )
- return;
- showDesktopNotification(data);
- }
- });
-
- return () => {
- socket.disconnect();
- };
- }, [contactId]);
-
- const updateUnreadMessagesCount = data => {
- setContacts(prevState => {
- const contactIndex = prevState.findIndex(
- contact => contact.id === data.message.contactId
- );
-
- if (contactIndex !== -1) {
- let aux = [...prevState];
- aux[contactIndex].unreadMessages++;
- aux[contactIndex].lastMessage = data.message.messageBody;
- aux.unshift(aux.splice(contactIndex, 1)[0]);
- return aux;
- } else {
- return [data.contact, ...prevState];
- }
- });
- };
-
- const showDesktopNotification = data => {
- const options = {
- body: `${data.message.messageBody} - ${format(new Date(), "HH:mm")}`,
- icon: data.contact.profilePicUrl,
- };
- new Notification(`Mensagem de ${data.contact.name}`, options);
- document.getElementById("sound").play();
- };
-
- const resetUnreadMessages = contactId => {
- setContacts(prevState => {
- let aux = [...prevState];
- let contactIndex = aux.findIndex(contact => contact.id === +contactId);
- aux[contactIndex].unreadMessages = 0;
-
- return aux;
- });
- };
-
- const handleSelectContact = (e, contact) => {
- history.push(`/chat/${contact.id}`);
- };
-
- const handleSearchContact = e => {
- // let searchTerm = e.target.value.toLowerCase();
- setSearchParam(e.target.value.toLowerCase());
- };
-
- const handleShowContactModal = e => {
- setModalOpen(true);
- };
-
- const handleAddContact = async contact => {
- try {
- const res = await api.post("/contacts", contact);
- setContacts(prevState => [res.data, ...prevState]);
- setModalOpen(false);
- console.log(res.data);
- } catch (err) {
- if (err.response.status === 422) {
- console.log("deu erro", err.response);
- alert(err.response.data.message);
- } else {
- alert(err);
- }
- }
- };
-
- return (
-
-
-
-
-
-
-
-
-
-
-
- {contacts.map((contact, index) => (
-
- handleSelectContact(e, contact)}
- selected={contactId && +contactId === contact.id}
- >
-
-
-
-
-
- {contact.name}
-
- {contact.lastMessage && (
-
- {format(parseISO(contact.updatedAt), "HH:mm")}
-
- )}
-
- }
- secondary={
-
-
- {contact.lastMessage ||
}
-
-
-
- }
- />
-
-
-
- ))}
-
- {loading ? (
-
-
-
- ) : null}
-
-
-
-
-
-
- );
-};
-
-export default ContactsList;
diff --git a/frontend/src/pages/Chat/components/MessagesInput/MessagesInput.js b/frontend/src/pages/Chat/components/MessagesInput/MessagesInput.js
index a1c644d..3bf99f7 100644
--- a/frontend/src/pages/Chat/components/MessagesInput/MessagesInput.js
+++ b/frontend/src/pages/Chat/components/MessagesInput/MessagesInput.js
@@ -102,7 +102,7 @@ const useStyles = makeStyles(theme => ({
const MessagesInput = ({ searchParam }) => {
const classes = useStyles();
- const { contactId } = useParams();
+ const { ticketId } = useParams();
const userId = localStorage.getItem("userId");
const username = localStorage.getItem("username");
@@ -120,7 +120,7 @@ const MessagesInput = ({ searchParam }) => {
setShowEmoji(false);
setMedia({});
};
- }, [contactId]);
+ }, [ticketId]);
const handleChangeInput = e => {
setInputMessage(e.target.value);
@@ -157,10 +157,10 @@ const MessagesInput = ({ searchParam }) => {
const formData = new FormData();
formData.append("media", media.raw);
formData.append("userId", userId);
- formData.append("messageBody", media.name);
+ formData.append("body", media.name);
try {
- await api.post(`/messages/${contactId}`, formData);
+ await api.post(`/messages/${ticketId}`, formData);
} catch (err) {
console.log(err);
alert(err);
@@ -176,10 +176,10 @@ const MessagesInput = ({ searchParam }) => {
read: 1,
userId: userId,
mediaUrl: "",
- messageBody: `${username}: ${inputMessage.trim()}`,
+ body: `${username}: ${inputMessage.trim()}`,
};
try {
- await api.post(`/messages/${contactId}`, message);
+ await api.post(`/messages/${ticketId}`, message);
} catch (err) {
alert(err);
}
@@ -218,10 +218,10 @@ const MessagesInput = ({ searchParam }) => {
const filename = `${new Date().getTime()}.mp3`;
console.log(blob);
formData.append("media", blob, filename);
- formData.append("messageBody", filename);
+ formData.append("body", filename);
formData.append("userId", userId);
try {
- await api.post(`/messages/${contactId}`, formData);
+ await api.post(`/messages/${ticketId}`, formData);
} catch (err) {
console.log(err);
alert(err);
diff --git a/frontend/src/pages/Chat/components/MessagesList/MessagesList.js b/frontend/src/pages/Chat/components/MessagesList/MessagesList.js
index b1000e7..07a7c22 100644
--- a/frontend/src/pages/Chat/components/MessagesList/MessagesList.js
+++ b/frontend/src/pages/Chat/components/MessagesList/MessagesList.js
@@ -1,5 +1,5 @@
import React, { useState, useEffect, useRef } from "react";
-import { useParams } from "react-router-dom";
+import { useParams, useHistory } from "react-router-dom";
import { isSameDay, parseISO, format } from "date-fns";
import openSocket from "socket.io-client";
@@ -11,13 +11,11 @@ import AccessTimeIcon from "@material-ui/icons/AccessTime";
import CircularProgress from "@material-ui/core/CircularProgress";
import DoneIcon from "@material-ui/icons/Done";
import DoneAllIcon from "@material-ui/icons/DoneAll";
-import SearchIcon from "@material-ui/icons/Search";
-import InputBase from "@material-ui/core/InputBase";
import Card from "@material-ui/core/Card";
import CardHeader from "@material-ui/core/CardHeader";
-import IconButton from "@material-ui/core/IconButton";
-import MoreVertIcon from "@material-ui/icons/MoreVert";
+import ReplayIcon from "@material-ui/icons/Replay";
import Avatar from "@material-ui/core/Avatar";
+import Button from "@material-ui/core/Button";
import { green } from "@material-ui/core/colors";
import whatsBackground from "../../../../Images/wa-background.png";
@@ -40,32 +38,13 @@ const useStyles = makeStyles(theme => ({
flex: "none",
},
- messagesSearchInputWrapper: {
- margin: 20,
- display: "flex",
- marginLeft: "auto",
- background: "#fff",
- borderRadius: 40,
- paddingRight: 4,
- width: 250,
- },
-
- messagesSearchInput: {
- border: "none",
- flex: 1,
- borderRadius: 30,
- },
-
- searchIcon: {
- color: "grey",
- marginLeft: 6,
+ actionButtons: {
marginRight: 6,
alignSelf: "center",
- },
-
- settingsIcon: {
- alignSelf: "center",
- padding: 8,
+ marginLeft: "auto",
+ "& > *": {
+ margin: theme.spacing(1),
+ },
},
messagesListWrapper: {
@@ -201,13 +180,16 @@ const useStyles = makeStyles(theme => ({
}));
const MessagesList = () => {
- const { contactId } = useParams();
+ const { ticketId } = useParams();
+ const history = useHistory();
const classes = useStyles();
const token = localStorage.getItem("token");
+ const userId = localStorage.getItem("userId");
const [loading, setLoading] = useState(true);
const [contact, setContact] = useState({});
+ const [ticket, setTicket] = useState({});
const [messagesList, setMessagesList] = useState([]);
const [hasMore, setHasMore] = useState(false);
const [searchParam, setSearchParam] = useState("");
@@ -223,10 +205,11 @@ const MessagesList = () => {
const delayDebounceFn = setTimeout(() => {
const fetchMessages = async () => {
try {
- const res = await api.get("/messages/" + contactId, {
+ const res = await api.get("/messages/" + ticketId, {
params: { searchParam, pageNumber },
});
setContact(res.data.contact);
+ setTicket(res.data.ticket);
setMessagesList(prevMessages => {
return [...res.data.messages, ...prevMessages];
});
@@ -243,12 +226,12 @@ const MessagesList = () => {
fetchMessages();
}, 1000);
return () => clearTimeout(delayDebounceFn);
- }, [searchParam, pageNumber, contactId, token]);
+ }, [searchParam, pageNumber, ticketId, token]);
useEffect(() => {
const socket = openSocket(process.env.REACT_APP_BACKEND_URL);
- socket.emit("joinChatBox", contactId, () => {});
+ socket.emit("joinChatBox", ticketId, () => {});
socket.on("appMessage", data => {
if (data.action === "create") {
@@ -265,7 +248,7 @@ const MessagesList = () => {
setPageNumber(1);
setMessagesList([]);
};
- }, [contactId]);
+ }, [ticketId]);
const handleSearch = e => {
setSearchParam(e.target.value);
@@ -340,6 +323,18 @@ const MessagesList = () => {
}
};
+ const handleUpdateTicketStatus = async (status, userId) => {
+ try {
+ await api.put(`/tickets/${ticketId}`, {
+ status: status,
+ userId: userId || null,
+ });
+ } catch (err) {
+ console.log(err);
+ }
+ history.push("/chat");
+ };
+
const renderMessageAck = message => {
if (message.ack === 0) {
return
;
@@ -401,13 +396,13 @@ const MessagesList = () => {
const renderMessages = () => {
if (messagesList.length > 0) {
const viewMessagesList = messagesList.map((message, index) => {
- if (message.userId === 0) {
+ if (!message.userId) {
return [
renderDailyTimestamps(message, index),
{message.mediaUrl && checkMessaageMedia(message)}
- {message.messageBody}
+ {message.body}
{format(parseISO(message.createdAt), "HH:mm")}
@@ -420,7 +415,7 @@ const MessagesList = () => {
{message.mediaUrl && checkMessaageMedia(message)}
- {message.messageBody}
+ {message.body}
{format(parseISO(message.createdAt), "HH:mm")}
{renderMessageAck(message)}
@@ -444,8 +439,8 @@ const MessagesList = () => {
titleTypographyProps={{ noWrap: true }}
subheaderTypographyProps={{ noWrap: true }}
avatar={}
- title={contact.name}
- subheader="Contact Status"
+ title={`${contact.name} #${ticket.id}`}
+ subheader={`Atribuído á ${ticket.userId}`}
/>
) : (
{
/>
)}
-
-
-
-
-
-
-
-
+
+ }
+ size="small"
+ onClick={e => handleUpdateTicketStatus("pending")}
+ >
+ Retornar
+
+
diff --git a/frontend/src/pages/Chat/components/TicketsList/TicketsList.js b/frontend/src/pages/Chat/components/TicketsList/TicketsList.js
new file mode 100644
index 0000000..385bb5e
--- /dev/null
+++ b/frontend/src/pages/Chat/components/TicketsList/TicketsList.js
@@ -0,0 +1,515 @@
+import React, { useState, useEffect } from "react";
+import { useHistory, useParams } from "react-router-dom";
+import api from "../../../../util/api";
+import openSocket from "socket.io-client";
+
+import { parseISO, format } from "date-fns";
+
+import profileDefaultPic from "../../../../Images/profile_default.png";
+
+import { makeStyles } from "@material-ui/core/styles";
+import { green } from "@material-ui/core/colors";
+import CircularProgress from "@material-ui/core/CircularProgress";
+import Paper from "@material-ui/core/Paper";
+import List from "@material-ui/core/List";
+import ListItem from "@material-ui/core/ListItem";
+import ListItemText from "@material-ui/core/ListItemText";
+import ListItemAvatar from "@material-ui/core/ListItemAvatar";
+import Typography from "@material-ui/core/Typography";
+import Avatar from "@material-ui/core/Avatar";
+// import AddIcon from "@material-ui/icons/Add";
+import Divider from "@material-ui/core/Divider";
+import Badge from "@material-ui/core/Badge";
+import SearchIcon from "@material-ui/icons/Search";
+import InputBase from "@material-ui/core/InputBase";
+import Button from "@material-ui/core/Button";
+// import Fab from "@material-ui/core/Fab";
+// import AddContactModal from "../AddContact/AddContactModal";
+
+import Tabs from "@material-ui/core/Tabs";
+import Tab from "@material-ui/core/Tab";
+import MoveToInboxIcon from "@material-ui/icons/MoveToInbox";
+import CheckCircleOutlineIcon from "@material-ui/icons/CheckCircleOutline";
+
+const useStyles = makeStyles(theme => ({
+ contactsWrapper: {
+ display: "flex",
+ height: "100%",
+ flexDirection: "column",
+ overflow: "hidden",
+ },
+
+ contactsHeader: {
+ display: "flex",
+ backgroundColor: "#eee",
+ borderBottomLeftRadius: 0,
+ borderBottomRightRadius: 0,
+ borderTopRightRadius: 0,
+ },
+
+ settingsIcon: {
+ alignSelf: "center",
+ marginLeft: "auto",
+ padding: 8,
+ },
+
+ openTicketsList: {
+ position: "relative",
+ borderTopLeftRadius: 0,
+ borderTopRightRadius: 0,
+ borderBottomRightRadius: 0,
+ height: "50%",
+ overflowY: "scroll",
+ "&::-webkit-scrollbar": {
+ width: "8px",
+ },
+ "&::-webkit-scrollbar-thumb": {
+ boxShadow: "inset 0 0 6px rgba(0, 0, 0, 0.3)",
+ backgroundColor: "#e8e8e8",
+ },
+ },
+
+ closedTicketsList: {
+ position: "relative",
+ borderTopLeftRadius: 0,
+ borderTopRightRadius: 0,
+ borderBottomRightRadius: 0,
+ flex: 1,
+ overflowY: "scroll",
+ "&::-webkit-scrollbar": {
+ width: "8px",
+ },
+ "&::-webkit-scrollbar-thumb": {
+ boxShadow: "inset 0 0 6px rgba(0, 0, 0, 0.3)",
+ backgroundColor: "#e8e8e8",
+ },
+ },
+
+ ticketsListHeader: {
+ display: "flex",
+ // flexShrink: 0,
+ // -webkitBoxAlign: "center",
+ alignItems: "center",
+ fontWeight: 600,
+ fontSize: "16px",
+ height: "56px",
+ // backgroundColor: "#eee",
+ color: "rgb(67, 83, 105)",
+ padding: "0px 24px",
+ borderBottom: "1px solid rgba(0, 0, 0, 0.12)",
+ },
+
+ ticketsCount: {
+ fontWeight: "normal",
+ color: "rgb(104, 121, 146)",
+ marginLeft: "8px",
+ fontSize: "14px",
+ },
+
+ ticket: {
+ position: "relative",
+ "& .hidden-button": {
+ display: "none",
+ },
+ "&:hover .hidden-button": {
+ display: "flex",
+ position: "absolute",
+ left: "50%",
+ },
+ },
+
+ contactsSearchBox: {
+ position: "relative",
+ background: "#fafafa",
+ padding: "10px 13px",
+ },
+
+ serachInputWrapper: {
+ background: "#fff",
+ display: "flex",
+ borderRadius: 40,
+ padding: 4,
+ },
+
+ searchIcon: {
+ color: "grey",
+ marginLeft: 6,
+ marginRight: 6,
+ alignSelf: "center",
+ },
+
+ contactsSearchInput: {
+ flex: 1,
+ border: "none",
+ borderRadius: 30,
+ },
+
+ contactNameWrapper: {
+ display: "flex",
+ // display: "inline",
+ },
+
+ lastMessageTime: {
+ marginLeft: "auto",
+ },
+
+ contactLastMessage: {
+ paddingRight: 20,
+ },
+
+ newMessagesCount: {
+ alignSelf: "center",
+ marginRight: 8,
+ marginLeft: "auto",
+ },
+
+ badgeStyle: {
+ color: "white",
+ backgroundColor: green[500],
+ },
+ circleLoading: {
+ color: green[500],
+ opacity: "70%",
+ position: "absolute",
+ top: 0,
+ left: "50%",
+ marginTop: 12,
+ // marginLeft: -12,
+ },
+ fabButton: {
+ position: "absolute",
+ zIndex: 1,
+ bottom: 20,
+ left: 0,
+ right: 0,
+ margin: "0 auto",
+ },
+}));
+
+const TicketsList = () => {
+ const classes = useStyles();
+ const token = localStorage.getItem("token");
+ const userId = +localStorage.getItem("userId");
+ const { ticketId } = useParams();
+ const [tickets, setTickets] = useState([]);
+ const [loading, setLoading] = useState();
+ const [searchParam, setSearchParam] = useState("");
+ const [tab, setTab] = useState("open");
+
+ // const [modalOpen, setModalOpen] = useState(false);
+
+ const history = useHistory();
+
+ useEffect(() => {
+ if (!("Notification" in window)) {
+ console.log("This browser doesn't support notifications");
+ } else {
+ Notification.requestPermission();
+ }
+ }, []);
+
+ useEffect(() => {
+ setLoading(true);
+ const delayDebounceFn = setTimeout(() => {
+ const fetchContacts = async () => {
+ try {
+ const res = await api.get("/tickets", {
+ params: { searchParam, status: tab },
+ });
+ setTickets(res.data);
+ setLoading(false);
+ } catch (err) {
+ console.log(err);
+ }
+ };
+ fetchContacts();
+ }, 1000);
+ return () => clearTimeout(delayDebounceFn);
+ }, [searchParam, token, tab]);
+
+ useEffect(() => {
+ const socket = openSocket(process.env.REACT_APP_BACKEND_URL);
+
+ socket.emit("joinNotification");
+
+ socket.on("ticket", data => {
+ if (data.action === "updateUnread") {
+ resetUnreadMessages(data.ticketId);
+ }
+ if (data.action === "updateStatus") {
+ updateTicketStatus(data);
+ }
+ });
+
+ socket.on("appMessage", data => {
+ if (data.action === "create") {
+ updateUnreadMessagesCount(data);
+ if (
+ ticketId &&
+ data.message.ticketId === +ticketId &&
+ document.visibilityState === "visible"
+ )
+ return;
+ showDesktopNotification(data);
+ }
+ });
+
+ return () => {
+ socket.disconnect();
+ };
+ }, [ticketId]);
+
+ const updateUnreadMessagesCount = data => {
+ setTickets(prevState => {
+ const ticketIndex = prevState.findIndex(
+ ticket => ticket.id === data.message.ticketId
+ );
+
+ if (ticketIndex !== -1) {
+ let aux = [...prevState];
+ aux[ticketIndex].unreadMessages++;
+ aux[ticketIndex].lastMessage = data.message.body;
+ aux.unshift(aux.splice(ticketIndex, 1)[0]);
+ return aux;
+ } else {
+ return [data.ticket, ...prevState];
+ }
+ });
+ };
+
+ const updateTicketStatus = data => {
+ setTickets(prevState => {
+ const ticketIndex = prevState.findIndex(
+ ticket => ticket.id === data.ticket.id
+ );
+
+ if (ticketIndex !== -1) {
+ let aux = [...prevState];
+ aux[ticketIndex] = data.ticket;
+ return aux;
+ } else {
+ return [data.ticket, ...prevState];
+ }
+ });
+ };
+
+ const showDesktopNotification = data => {
+ console.log("data", data);
+ const options = {
+ body: `${data.message.body} - ${format(new Date(), "HH:mm")}`,
+ icon: data.contact.profilePicUrl,
+ };
+ new Notification(`Mensagem de ${data.contact.name}`, options);
+ document.getElementById("sound").play();
+ };
+
+ const resetUnreadMessages = ticketId => {
+ setTickets(prevState => {
+ let aux = [...prevState];
+ let ticketIndex = aux.findIndex(ticket => ticket.id === +ticketId);
+ aux[ticketIndex].unreadMessages = 0;
+
+ return aux;
+ });
+ };
+
+ const handleSelectTicket = (e, ticket) => {
+ history.push(`/chat/${ticket.id}`);
+ };
+
+ const handleSearchContact = e => {
+ // let searchTerm = e.target.value.toLowerCase();
+ setSearchParam(e.target.value.toLowerCase());
+ };
+
+ const handleChangeTab = (event, newValue) => {
+ setTab(newValue);
+ };
+
+ const handleAcepptTicket = async ticketId => {
+ try {
+ await api.put(`/tickets/${ticketId}`, {
+ status: "open",
+ userId: userId,
+ });
+ } catch (err) {
+ alert(err);
+ }
+ };
+
+ const countTickets = status => {
+ const ticketsFound = tickets.filter(ticket => ticket.status === status)
+ .length;
+
+ if (ticketsFound === 0) return "";
+ return ticketsFound;
+ };
+
+ const renderTickets = (status, userId) => {
+ const viewTickets = tickets.map(
+ (ticket, index) =>
+ ticket.status === status && (
+
+ {
+ if (ticket.status === "pending") return;
+ handleSelectTicket(e, ticket);
+ }}
+ selected={ticketId && +ticketId === ticket.id}
+ className={classes.ticket}
+ >
+
+
+
+
+
+ {ticket.Contact.name}
+
+ {ticket.lastMessage && (
+
+ {format(parseISO(ticket.updatedAt), "HH:mm")}
+
+ )}
+
+ }
+ secondary={
+
+
+ {ticket.lastMessage ||
}
+
+
+
+ }
+ />
+ {ticket.status === "pending" ? (
+
+ ) : null}
+
+
+
+ )
+ );
+
+ return viewTickets;
+ };
+
+ return (
+
+
+
+ }
+ label="Caixa de Entrada"
+ />
+ }
+ label="Resolvidos"
+ />
+
+
+
+
+
+
+
+ {loading ? (
+
+
+
+ ) : null}
+
+ {tab === "open" ? (
+ <>
+
+
+
+ Meus tickets
+
+ {countTickets("open")}
+
+
+ {renderTickets("open")}
+
+
+
+
+
+ Aguardando
+
+ {countTickets("pending")}
+
+
+ {renderTickets("pending")}
+
+
+ >
+ ) : (
+
+ {renderTickets("closed")}
+
+ )}
+
+
+
+ );
+};
+
+export default TicketsList;
diff --git a/frontend/src/pages/Home/Dashboard.js b/frontend/src/pages/Home/Dashboard.js
index c27a883..033f34a 100644
--- a/frontend/src/pages/Home/Dashboard.js
+++ b/frontend/src/pages/Home/Dashboard.js
@@ -1,12 +1,9 @@
import React from "react";
-import MainDrawer from "../../components/Layout/MainDrawer";
const Dashboard = () => {
return (
-
- Todo Dashboard
-
+
Todo Dashboard
);
};
diff --git a/frontend/src/pages/WhatsAuth/WhatsAuth.js b/frontend/src/pages/WhatsAuth/WhatsAuth.js
index 9210c72..0ce3245 100644
--- a/frontend/src/pages/WhatsAuth/WhatsAuth.js
+++ b/frontend/src/pages/WhatsAuth/WhatsAuth.js
@@ -1,7 +1,6 @@
import React, { useState, useEffect } from "react";
import { useHistory } from "react-router-dom";
import api from "../../util/api";
-import MainDrawer from "../../components/Layout/MainDrawer";
import openSocket from "socket.io-client";
import { makeStyles } from "@material-ui/core/styles";
@@ -89,36 +88,34 @@ const WhatsAuth = () => {
return (
-
-
-
-
-
-
- {session.status === "pending" ? (
-
-
-
-
-
- ) : (
-
-
-
-
-
- )}
+
+
+
+
+
+ {session.status === "pending" ? (
+
+
+
+
+
+ ) : (
+
+
+
+
+
+ )}
- {/*
+ {/*
paper2
*/}
-
-
-
-
-
+
+
+
+
);
};
diff --git a/frontend/src/routes.js b/frontend/src/routes.js
index 0d64741..9d5659d 100644
--- a/frontend/src/routes.js
+++ b/frontend/src/routes.js
@@ -3,6 +3,7 @@ import { BrowserRouter, Route, Switch, Redirect } from "react-router-dom";
import { AuthContext, AuthProvider } from "./Context/Auth/AuthContext";
+import MainDrawer from "./components/Layout/MainDrawer";
import Dashboard from "./pages/Home/Dashboard";
import Chat from "./pages/Chat/Chat";
import Profile from "./pages/Profile/Profile";
@@ -77,13 +78,14 @@ const Routes = () => {
-
-
-
-
-
+
+
+
+
+
+