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}`} /> ) : ( { /> )} -
- - -
-
- - - +
+ +
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 = () => { - - - - - + + + + + +