From 144bb6db94bfaa22b8d1cf921a30271c1dbec754 Mon Sep 17 00:00:00 2001 From: adriano Date: Thu, 7 Mar 2024 18:17:02 -0300 Subject: [PATCH 01/23] update before git pull --- frontend/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/server.js b/frontend/server.js index a05ba32..cd23e05 100644 --- a/frontend/server.js +++ b/frontend/server.js @@ -6,4 +6,4 @@ app.use(express.static(path.join(__dirname, "build"))); app.get("/*", function (req, res) { res.sendFile(path.join(__dirname, "build", "index.html")); }); -app.listen(3333); +app.listen(3337); From a5d3f19e1abfc18dbd0ea52ebf8fd60e622a48dc Mon Sep 17 00:00:00 2001 From: willian-pessoa Date: Wed, 8 May 2024 18:02:31 -0300 Subject: [PATCH 02/23] refactor: criado conexao web socket global e movido alguns listeners para ela --- .../components/NotificationsPopOver/index.js | 91 ++++++++++--------- .../src/components/TicketListItem/index.js | 14 +-- frontend/src/components/TicketsList/index.js | 39 +++++--- frontend/src/hooks/useAuth.js/index.js | 40 ++++---- frontend/src/hooks/useWhatsApps/index.js | 12 ++- frontend/src/layout/MainListItems.js | 11 ++- frontend/src/services/socket.js | 6 ++ 7 files changed, 122 insertions(+), 91 deletions(-) create mode 100644 frontend/src/services/socket.js diff --git a/frontend/src/components/NotificationsPopOver/index.js b/frontend/src/components/NotificationsPopOver/index.js index 1e46dd1..0871f7a 100644 --- a/frontend/src/components/NotificationsPopOver/index.js +++ b/frontend/src/components/NotificationsPopOver/index.js @@ -2,7 +2,8 @@ import React, { useState, useRef, useEffect, useContext } from "react" import { useHistory } from "react-router-dom" import { format } from "date-fns" -import openSocket from "socket.io-client" +//import openSocket from "socket.io-client" +import { socket } from "../../services/socket" import useSound from "use-sound" import Popover from "@material-ui/core/Popover" @@ -115,24 +116,24 @@ const NotificationsPopOver = () => { useEffect(() => { const fetchSession = async () => { - try { - const { data } = await api.get('/settings') - setSettings(data.settings) - } catch (err) { - toastError(err) - } + try { + const { data } = await api.get('/settings') + setSettings(data.settings) + } catch (err) { + toastError(err) + } } fetchSession() - }, []) + }, []) - const getSettingValue = (key) => { + const getSettingValue = (key) => { const { value } = settings.find((s) => s.key === key) return value - } + } useEffect(() => { - const socket = openSocket(process.env.REACT_APP_BACKEND_URL) + //const socket = openSocket(process.env.REACT_APP_BACKEND_URL) socket.on("reload_page", (data) => { @@ -193,7 +194,8 @@ const NotificationsPopOver = () => { return () => { - socket.disconnect() + socket.removeAllListeners('reload_page'); + socket.removeAllListeners('onlineStatus'); } }, [user.id, handleLogout, user.profile]) @@ -201,12 +203,17 @@ const NotificationsPopOver = () => { useEffect(() => { - const socket = openSocket(process.env.REACT_APP_BACKEND_URL) + //const socket = openSocket(process.env.REACT_APP_BACKEND_URL) - socket.on("connect", () => socket.emit("joinNotification")) + const onConnectNotifications = () => { + socket.emit("joinNotification") + } + onConnectNotifications() - socket.on("ticket", data => { + socket.on("connect", onConnectNotifications) + + const onTicketNotifications = data => { if (data.action === "updateUnread" || data.action === "delete") { @@ -232,25 +239,18 @@ const NotificationsPopOver = () => { return prevState }) } - }) - - socket.on("appMessage", data => { - + } + socket.on("ticket", onTicketNotifications) + const onAppMessageNotifications = data => { if ( data.action === "create" && !data.message.read && (data.ticket.userId === user?.id || !data.ticket.userId) ) { - - - setNotifications(prevState => { - - - // prevState.forEach((e)=>{ // // }) @@ -265,8 +265,6 @@ const NotificationsPopOver = () => { return [data.ticket, ...prevState] }) - - const shouldNotNotificate = (data.message.ticketId === ticketIdRef.current && document.visibilityState === "visible") || (data.ticket.userId && data.ticket.userId !== user?.id) || data.ticket.isGroup || !data.ticket.userId @@ -275,20 +273,25 @@ const NotificationsPopOver = () => { handleNotifications(data) } - }) + } - socket.on('notifyPeding', data =>{ - if(settings?.length > 0 && getSettingValue('notificationTransferQueue') === 'enabled') handleNotifications("", data); + socket.on("appMessage", onAppMessageNotifications) + + socket.on('notifyPeding', data => { + if (settings?.length > 0 && getSettingValue('notificationTransferQueue') === 'enabled') handleNotifications("", data); }); return () => { - socket.disconnect() + socket.off('connect', onConnectNotifications); + socket.off('ticket', onTicketNotifications); + socket.off('appMessage', onAppMessageNotifications); + socket.removeAllListeners('notifyPeding'); } }, [user, settings]) - const handleNotifications = (data, notify) => { + const handleNotifications = (data, notify) => { let isQueue = false; - if(!notify){ + if (!notify) { const { message, contact, ticket } = data const options = { @@ -301,14 +304,14 @@ const NotificationsPopOver = () => { const notification = new Notification( `${i18n.t("tickets.notification.message")} ${contact.name}`, options - ) - - notification.onclick = e => { - e.preventDefault() + ) + + notification.onclick = e => { + e.preventDefault() window.focus() historyRef.current.push(`/tickets/${ticket.id}`) } - + setDesktopNotifications(prevState => { const notfiticationIndex = prevState.findIndex( n => n.tag === notification.tag @@ -319,15 +322,15 @@ const NotificationsPopOver = () => { } return [notification, ...prevState] }) - }else{ - user.queues.forEach(queue =>{ - if(queue.id === notify.data?.queue?.id){ + } else { + user.queues.forEach(queue => { + if (queue.id === notify.data?.queue?.id) { isQueue = true; } }) - if(!isQueue){ + if (!isQueue) { return; - }else { + } else { const notification = new Notification(`${i18n.t("tickets.notification.messagePeding")} ${notify.data?.queue?.name}`); notification.onclick = e => { e.preventDefault() @@ -346,7 +349,7 @@ const NotificationsPopOver = () => { return [notification, ...prevState] }) } - } + } soundAlertRef.current() } diff --git a/frontend/src/components/TicketListItem/index.js b/frontend/src/components/TicketListItem/index.js index 0d71944..931be34 100644 --- a/frontend/src/components/TicketListItem/index.js +++ b/frontend/src/components/TicketListItem/index.js @@ -22,7 +22,8 @@ import MarkdownWrapper from "../MarkdownWrapper" import { Tooltip } from "@material-ui/core" import { AuthContext } from "../../context/Auth/AuthContext" import toastError from "../../errors/toastError" -import openSocket from 'socket.io-client' +//import openSocket from 'socket.io-client' +import { socket } from "../../services/socket" const useStyles = makeStyles(theme => ({ ticket: { @@ -151,7 +152,7 @@ const TicketListItem = ({ ticket, remoteTicketsControll, settings }) => { useEffect(() => { - const socket = openSocket(process.env.REACT_APP_BACKEND_URL) + //const socket = openSocket(process.env.REACT_APP_BACKEND_URL) socket.on('remoteTickesControll', (data) => { console.log('REMOTE TICKETS CONTROLL UPDATE2: ', data.tickets) @@ -160,8 +161,7 @@ const TicketListItem = ({ ticket, remoteTicketsControll, settings }) => { } }) - - socket.on('settings', (data) => { + const onSettingsTicketListItem = (data) => { if (data.action === 'update') { setSettings((prevState) => { const aux = [...prevState] @@ -170,11 +170,13 @@ const TicketListItem = ({ ticket, remoteTicketsControll, settings }) => { return aux }) } - }) + } + socket.on('settings', onSettingsTicketListItem) return () => { - socket.disconnect() + socket.removeAllListeners('remoteTickesControll'); + socket.off('settings', onSettingsTicketListItem); } }, []) diff --git a/frontend/src/components/TicketsList/index.js b/frontend/src/components/TicketsList/index.js index a481700..36dee0a 100644 --- a/frontend/src/components/TicketsList/index.js +++ b/frontend/src/components/TicketsList/index.js @@ -1,7 +1,7 @@ import React, { useState, useEffect, useReducer, useContext } from "react" - -import openSocket from "socket.io-client" +//import openSocket from "socket.io-client" +import { socket } from "../../services/socket" import { makeStyles } from "@material-ui/core/styles" import List from "@material-ui/core/List" @@ -243,7 +243,7 @@ const TicketsList = (props) => { // if (tab=='search')return - const socket = openSocket(process.env.REACT_APP_BACKEND_URL) + //const socket = openSocket(process.env.REACT_APP_BACKEND_URL) const shouldUpdateTicket = ticket => (!ticket.userId || ticket.userId === user?.id || showAll) && @@ -252,18 +252,19 @@ const TicketsList = (props) => { const notBelongsToUserQueues = ticket => ticket.queueId && selectedQueueIds.indexOf(ticket.queueId) === -1 - socket.on("connect", () => { + const onConnectTicketList = () => { if (status) { socket.emit("joinTickets", status) } else { socket.emit("joinNotification") } + } - }) + onConnectTicketList() + socket.on("connect", onConnectTicketList) - - socket.on("ticket", data => { + const onTicketTicketList = data => { if (data.action === "updateUnread") { @@ -292,10 +293,11 @@ const TicketsList = (props) => { if (data.action === "delete") { dispatch({ type: "DELETE_TICKET", payload: data.ticketId }) } - }) + } + socket.on("ticket", onTicketTicketList) - socket.on("appMessage", data => { + const onAppMessageTicketList = data => { if (data.action === "create" && shouldUpdateTicket(data.ticket)) { @@ -307,7 +309,9 @@ const TicketsList = (props) => { payload: data, }) } - }) + } + + socket.on("appMessage", onAppMessageTicketList) socket.on("contact", data => { if (data.action === "update") { @@ -326,8 +330,7 @@ const TicketsList = (props) => { } }) - - socket.on('settings', (data) => { + const onSettingsTicketList = (data) => { if (data.action === 'update') { setSettings((prevState) => { const aux = [...prevState] @@ -336,11 +339,17 @@ const TicketsList = (props) => { return aux }) } - }) + } + socket.on('settings', onSettingsTicketList) return () => { - socket.disconnect() + socket.off("ticket", onTicketTicketList) + socket.off('appMessage', onAppMessageTicketList); + socket.removeAllListeners("contact") + socket.off('connect', onConnectTicketList); + socket.off('settings', onSettingsTicketList); + socket.removeAllListeners('remoteTickesControll'); } }, [status, showAll, user, selectedQueueIds, tab]) @@ -349,7 +358,7 @@ const TicketsList = (props) => { if (typeof updateCount === "function") { updateCount(ticketsList.length) } - if (ticketsList && status === "pending"){ + if (ticketsList && status === "pending") { setTickets(ticketsList) } // else{ diff --git a/frontend/src/hooks/useAuth.js/index.js b/frontend/src/hooks/useAuth.js/index.js index e2da363..6e3c7fb 100644 --- a/frontend/src/hooks/useAuth.js/index.js +++ b/frontend/src/hooks/useAuth.js/index.js @@ -1,6 +1,7 @@ import { useState, useEffect } from 'react' import { useHistory } from 'react-router-dom' -import openSocket from 'socket.io-client' +//import openSocket from 'socket.io-client' +import { socket } from '../../services/socket' import { toast } from 'react-toastify' @@ -62,19 +63,19 @@ const useAuth = () => { useEffect(() => { const token = localStorage.getItem('token') - ;(async () => { - if (token) { - try { - const { data } = await api.post('/auth/refresh_token') - api.defaults.headers.Authorization = `Bearer ${data.token}` - setIsAuth(true) - setUser(data.user) - } catch (err) { - toastError(err) + ; (async () => { + if (token) { + try { + const { data } = await api.post('/auth/refresh_token') + api.defaults.headers.Authorization = `Bearer ${data.token}` + setIsAuth(true) + setUser(data.user) + } catch (err) { + toastError(err) + } } - } - setLoading(false) - })() + setLoading(false) + })() }, []) useEffect(() => { @@ -90,7 +91,7 @@ const useAuth = () => { }, []) useEffect(() => { - const socket = openSocket(process.env.REACT_APP_BACKEND_URL) + //const socket = openSocket(process.env.REACT_APP_BACKEND_URL) socket.on('user', (data) => { if (data.action === 'update' && data.user.id === user.id) { @@ -98,7 +99,7 @@ const useAuth = () => { } }) - socket.on('settings', (data) => { + const onSettingsAuth = (data) => { if (data.action === 'update') { setSetting((prevState) => { const aux = [...prevState] @@ -107,10 +108,13 @@ const useAuth = () => { return aux }) } - }) + } + + socket.on('settings', onSettingsAuth) return () => { - socket.disconnect() + socket.removeAllListeners('user'); + socket.off('settings', onSettingsAuth); } }, [user]) @@ -135,7 +139,7 @@ const useAuth = () => { const handleLogout = async () => { setLoading(true) - try { + try { await api.delete(`/auth/logout/${user.id}`); setIsAuth(false) diff --git a/frontend/src/hooks/useWhatsApps/index.js b/frontend/src/hooks/useWhatsApps/index.js index 1360ac1..fe4da0a 100644 --- a/frontend/src/hooks/useWhatsApps/index.js +++ b/frontend/src/hooks/useWhatsApps/index.js @@ -1,5 +1,7 @@ import { useState, useEffect, useReducer } from "react"; -import openSocket from "socket.io-client"; +//import openSocket from "socket.io-client"; +import { socket } from "../../services/socket"; + import toastError from "../../errors/toastError"; @@ -30,7 +32,7 @@ const reducer = (state, action) => { if (whatsAppIndex !== -1) { - if ('disabled' in whatsApp) { + if ('disabled' in whatsApp) { state[whatsAppIndex].disabled = whatsApp.disabled } else { @@ -126,7 +128,7 @@ const useWhatsApps = () => { }, []); useEffect(() => { - const socket = openSocket(process.env.REACT_APP_BACKEND_URL); + //const socket = openSocket(process.env.REACT_APP_BACKEND_URL); socket.on("whatsapp", data => { if (data.action === "update") { @@ -158,7 +160,9 @@ const useWhatsApps = () => { return () => { - socket.disconnect(); + socket.removeAllListeners('whatsapp'); + socket.removeAllListeners('whatsappSession'); + socket.removeAllListeners('whatsappSessionMonit'); }; }, []); diff --git a/frontend/src/layout/MainListItems.js b/frontend/src/layout/MainListItems.js index 03339d2..6530671 100644 --- a/frontend/src/layout/MainListItems.js +++ b/frontend/src/layout/MainListItems.js @@ -32,6 +32,7 @@ import { WhatsAppsContext } from '../context/WhatsApp/WhatsAppsContext' import { AuthContext } from '../context/Auth/AuthContext' import { Can } from '../components/Can' import openSocket from 'socket.io-client' +import { socket } from '../services/socket' import api from '../services/api' @@ -118,9 +119,9 @@ const MainListItems = (props) => { } useEffect(() => { - const socket = openSocket(process.env.REACT_APP_BACKEND_URL) + //const socket = openSocket(process.env.REACT_APP_BACKEND_URL) - socket.on('settings', (data) => { + const onSettingsMainListItem = (data) => { if (data.action === 'update') { setSettings((prevState) => { const aux = [...prevState] @@ -129,10 +130,12 @@ const MainListItems = (props) => { return aux }) } - }) + } + + socket.on('settings', onSettingsMainListItem) return () => { - socket.disconnect() + socket.off('settings', onSettingsMainListItem); } }, []) diff --git a/frontend/src/services/socket.js b/frontend/src/services/socket.js new file mode 100644 index 0000000..a458f57 --- /dev/null +++ b/frontend/src/services/socket.js @@ -0,0 +1,6 @@ +import { io } from 'socket.io-client'; + +// "undefined" means the URL will be computed from the `window.location` object +const URL = process.env.REACT_APP_BACKEND_URL + +export const socket = io(URL); \ No newline at end of file From 4d3cab53331a7397a46f8d7c5236fb638de8e9d5 Mon Sep 17 00:00:00 2001 From: willian-pessoa Date: Thu, 9 May 2024 09:01:21 -0300 Subject: [PATCH 03/23] refactor: mais tres ws connecoes movidas para conecao global --- frontend/src/components/MessagesList/index.js | 25 +++++++++---- frontend/src/components/Ticket/index.js | 35 +++++++++++++------ .../src/components/TicketsManager/index.js | 9 +++-- frontend/src/layout/MainListItems.js | 2 +- 4 files changed, 48 insertions(+), 23 deletions(-) diff --git a/frontend/src/components/MessagesList/index.js b/frontend/src/components/MessagesList/index.js index 7e9126c..438b7ad 100644 --- a/frontend/src/components/MessagesList/index.js +++ b/frontend/src/components/MessagesList/index.js @@ -1,7 +1,9 @@ import React, { useContext, useState, useEffect, useReducer, useRef } from "react" import { isSameDay, parseISO, format } from "date-fns" -import openSocket from "socket.io-client" +//import openSocket from "socket.io-client" +import { socket } from "../../services/socket" + import clsx from "clsx" import { AuthContext } from "../../context/Auth/AuthContext" @@ -34,7 +36,7 @@ import whatsBackground from "../../assets/wa-background.png" import api from "../../services/api" import toastError from "../../errors/toastError" -import { countTicketMsgContext } from "../../context/CountTicketMsgProvider/CountTicketMsgProvider" +import { countTicketMsgContext } from "../../context/CountTicketMsgProvider/CountTicketMsgProvider" const useStyles = makeStyles((theme) => ({ messagesListWrapper: { @@ -438,11 +440,17 @@ const MessagesList = ({ ticketId, isGroup }) => { }, [pageNumber, ticketId]) useEffect(() => { - const socket = openSocket(process.env.REACT_APP_BACKEND_URL) + //const socket = openSocket(process.env.REACT_APP_BACKEND_URL) - socket.on("connect", () => socket.emit("joinChatBox", ticketId)) + const onConnectMessagesList = () => { + socket.emit("joinChatBox", ticketId) + } - socket.on("appMessage", (data) => { + onConnectMessagesList() + + socket.on("connect", onConnectMessagesList) + + onAppMessageMessagesList = (data) => { if (data.action === "create") { @@ -454,10 +462,13 @@ const MessagesList = ({ ticketId, isGroup }) => { if (data.action === "update") { dispatch({ type: "UPDATE_MESSAGE", payload: data.message }) } - }) + } + + socket.on("appMessage", onAppMessageMessagesList) return () => { - socket.disconnect() + socket.off("connect", onConnectMessagesList) + socket.off("appMessage", onAppMessageMessagesList) } }, [ticketId]) diff --git a/frontend/src/components/Ticket/index.js b/frontend/src/components/Ticket/index.js index dbf78bf..cd6cb41 100644 --- a/frontend/src/components/Ticket/index.js +++ b/frontend/src/components/Ticket/index.js @@ -2,7 +2,9 @@ import React, { useState, useEffect } from "react" import { useParams, useHistory } from "react-router-dom" import { toast } from "react-toastify" -import openSocket from "socket.io-client" +//import openSocket from "socket.io-client" +import { socket } from "../../services/socket" + import clsx from "clsx" import { Paper, makeStyles } from "@material-ui/core" @@ -132,11 +134,15 @@ const Ticket = () => { }, []) useEffect(() => { - const socket = openSocket(process.env.REACT_APP_BACKEND_URL) + //const socket = openSocket(process.env.REACT_APP_BACKEND_URL) - socket.on("connect", () => socket.emit("joinChatBox", ticketId)) + const onConnectTicket = () => socket.emit("joinChatBox", ticketId) - socket.on("ticket", (data) => { + onConnectTicket() + + socket.on("connect", onConnectTicket) + + const onTicketTicket = (data) => { if (data.action === "update") { setTicket(data.ticket) } @@ -145,9 +151,11 @@ const Ticket = () => { toast.success("Ticket deleted sucessfully.") history.push("/tickets") } - }) + } - socket.on("contact", (data) => { + socket.on("ticket", onTicketTicket) + + const onContactTicket = (data) => { if (data.action === "update") { setContact((prevState) => { if (prevState.id === data.contact?.id) { @@ -156,9 +164,11 @@ const Ticket = () => { return prevState }) } - }) + } - socket.on("remoteTickesControllIdleOpen", (data) => { + socket.on("contact", onContactTicket) + + const onRemoteTicketsControllIdleOpenTicket = (data) => { if (data.action === "update") { let url_ticketId try { @@ -175,10 +185,15 @@ const Ticket = () => { console.log('error on try do the send seen: ', error) } } - }) + } + + socket.on("remoteTickesControllIdleOpen", onRemoteTicketsControllIdleOpenTicket) return () => { - socket.disconnect() + socket.off("connect", onConnectTicket) + socket.off("ticket", onTicketTicket) + socket.off("contact", onContactTicket) + socket.off("remoteTickesControllIdleOpen", onRemoteTicketsControllIdleOpenTicket) } }, [ticketId, history]) diff --git a/frontend/src/components/TicketsManager/index.js b/frontend/src/components/TicketsManager/index.js index 19b922b..18bd1c8 100644 --- a/frontend/src/components/TicketsManager/index.js +++ b/frontend/src/components/TicketsManager/index.js @@ -19,7 +19,6 @@ import FindInPageIcon from '@material-ui/icons/FindInPage' import FormControlLabel from "@material-ui/core/FormControlLabel" import Switch from "@material-ui/core/Switch" -import openSocket from "socket.io-client" import NewTicketModal from "../NewTicketModal" import TicketsList from "../TicketsList" @@ -193,13 +192,13 @@ const TicketsManager = () => { setTabOption(tab) - }, [tab, setTabOption]) + }, [tab, setTabOption]) useEffect(() => { if (settings?.length > 0 && getSettingValue('waitingTimeTickets') !== 'enabled') return - const calculateAverageTime = () => { + const calculateAverageTime = () => { if (tickets.length > 0) { const now = new Date() const differenceTime = tickets?.map(ticket => { @@ -222,10 +221,10 @@ const TicketsManager = () => { } else return '00:00' } - setWaitingTime(calculateAverageTime()) + setWaitingTime(calculateAverageTime()) const intervalId = setInterval(() => { - setWaitingTime(calculateAverageTime()) + setWaitingTime(calculateAverageTime()) }, 10000) return () => clearInterval(intervalId) diff --git a/frontend/src/layout/MainListItems.js b/frontend/src/layout/MainListItems.js index 6530671..eedb663 100644 --- a/frontend/src/layout/MainListItems.js +++ b/frontend/src/layout/MainListItems.js @@ -31,7 +31,7 @@ import { i18n } from '../translate/i18n' import { WhatsAppsContext } from '../context/WhatsApp/WhatsAppsContext' import { AuthContext } from '../context/Auth/AuthContext' import { Can } from '../components/Can' -import openSocket from 'socket.io-client' +//import openSocket from 'socket.io-client' import { socket } from '../services/socket' import api from '../services/api' From 5981f9dd5e56efd6ee05d1b85cea24b6e8c5d5ec Mon Sep 17 00:00:00 2001 From: willian-pessoa Date: Thu, 9 May 2024 15:31:30 -0300 Subject: [PATCH 04/23] refactor: mais 7 conexoes movidas para conexao ws global --- .../src/components/PositionModal/index.js | 28 +++++---- frontend/src/components/QrcodeModal/index.js | 24 ++++---- frontend/src/components/QueueModal/index.js | 14 +++-- .../src/components/QuickAnswersModal/index.js | 24 ++++---- .../components/TransferTicketModal/index.js | 19 +++--- frontend/src/pages/Campaign/index.js | 59 ++++++++++--------- frontend/src/pages/Connections/index.js | 26 ++++---- 7 files changed, 109 insertions(+), 85 deletions(-) diff --git a/frontend/src/components/PositionModal/index.js b/frontend/src/components/PositionModal/index.js index 29dcde5..d1f6f90 100644 --- a/frontend/src/components/PositionModal/index.js +++ b/frontend/src/components/PositionModal/index.js @@ -3,8 +3,8 @@ import React, { useState, useEffect, useRef, useContext } from "react" import * as Yup from "yup" import { Formik, Form, Field } from "formik" import { toast } from "react-toastify" -import openSocket from 'socket.io-client' - +//import openSocket from 'socket.io-client' +import { socket } from "../../services/socket" import { makeStyles, @@ -51,8 +51,8 @@ const useStyles = makeStyles((theme) => ({ })) const PositionSchema = Yup.object().shape({ - name: Yup.string() - .required("Required"), + name: Yup.string() + .required("Required"), }) const PositionModal = ({ @@ -66,14 +66,14 @@ const PositionModal = ({ const isMounted = useRef(true) const initialState = { - name: "", + name: "", } const [position, setPosition] = useState(initialState) // const [selectedQueueIds, setSelectedQueueIds] = useState([]) const { setting } = useContext(AuthContext) const [settings, setSettings] = useState(setting) - + useEffect(() => { return () => { @@ -87,9 +87,9 @@ const PositionModal = ({ useEffect(() => { - const socket = openSocket(process.env.REACT_APP_BACKEND_URL) + //const socket = openSocket(process.env.REACT_APP_BACKEND_URL) - socket.on('settings', (data) => { + const onSettingsPosition = (data) => { if (data.action === 'update') { setSettings((prevState) => { const aux = [...prevState] @@ -98,10 +98,12 @@ const PositionModal = ({ return aux }) } - }) + } + + socket.on('settings', onSettingsPosition) return () => { - socket.disconnect() + socket.off("settings", onSettingsPosition) } }, []) @@ -141,7 +143,7 @@ const PositionModal = ({ const handleSavePosition = async (values) => { try { - + if (positionId) { await api.put(`/positions/${positionId}`, values) handleClose() @@ -154,7 +156,7 @@ const PositionModal = ({ handleClose() toast.success("Cargo salvo com sucesso") } - + } catch (err) { toastError(err) } @@ -201,7 +203,7 @@ const PositionModal = ({ className={classes.textField} fullWidth /> - + {/*
{ ((settings && getSettingValue('quickAnswerByQueue') === 'enabled')) && ( diff --git a/frontend/src/components/QrcodeModal/index.js b/frontend/src/components/QrcodeModal/index.js index dcca527..4c8bd23 100644 --- a/frontend/src/components/QrcodeModal/index.js +++ b/frontend/src/components/QrcodeModal/index.js @@ -1,6 +1,8 @@ import React, { useEffect, useState, useContext } from "react"; import QRCode from "qrcode.react"; -import openSocket from "socket.io-client"; +//import openSocket from "socket.io-client"; +import { socket } from "../../services/socket"; + import toastError from "../../errors/toastError"; import { Dialog, DialogContent, Paper, Typography } from "@material-ui/core"; @@ -31,9 +33,9 @@ const QrcodeModal = ({ open, onClose, whatsAppId }) => { useEffect(() => { if (!whatsAppId) return; - const socket = openSocket(process.env.REACT_APP_BACKEND_URL); + //const socket = openSocket(process.env.REACT_APP_BACKEND_URL); - socket.on("whatsappSession", data => { + const onWhatsAppSessionQrCode = data => { if (data.action === "update" && data.session.id === whatsAppId) { setQrCode(data.session.qrcode); } @@ -42,21 +44,23 @@ const QrcodeModal = ({ open, onClose, whatsAppId }) => { onClose(); } - if (data.action === "error") { + if (data.action === "error") { - console.log('user.profile: ', user.profile) + console.log('user.profile: ', user.profile) - if(user.profile === 'master'){ + if (user.profile === 'master') { alert(data.msg) - } - + } + } - }); + } + + socket.on("whatsappSession", onWhatsAppSessionQrCode); return () => { - socket.disconnect(); + socket.off("whatsappSession", onWhatsAppSessionQrCode); }; }, [whatsAppId, onClose, user.profile]); diff --git a/frontend/src/components/QueueModal/index.js b/frontend/src/components/QueueModal/index.js index eb82ee8..776f68d 100644 --- a/frontend/src/components/QueueModal/index.js +++ b/frontend/src/components/QueueModal/index.js @@ -23,8 +23,8 @@ import { IconButton, InputAdornment } from "@material-ui/core" import { Colorize } from "@material-ui/icons" import { AuthContext } from '../../context/Auth/AuthContext' -import openSocket from 'socket.io-client' - +//import openSocket from 'socket.io-client' +import { socket } from "../../services/socket" const useStyles = makeStyles(theme => ({ @@ -92,9 +92,9 @@ const QueueModal = ({ open, onClose, queueId }) => { }, [setting]) useEffect(() => { - const socket = openSocket(process.env.REACT_APP_BACKEND_URL) + //const socket = openSocket(process.env.REACT_APP_BACKEND_URL) - socket.on('settings', (data) => { + const onSettingsQueueModal = (data) => { if (data.action === 'update') { setSettings((prevState) => { const aux = [...prevState] @@ -103,10 +103,12 @@ const QueueModal = ({ open, onClose, queueId }) => { return aux }) } - }) + } + + socket.on('settings', onSettingsQueueModal) return () => { - socket.disconnect() + socket.off("settings", onSettingsQueueModal) } }, []) diff --git a/frontend/src/components/QuickAnswersModal/index.js b/frontend/src/components/QuickAnswersModal/index.js index 10008f8..748c3ce 100644 --- a/frontend/src/components/QuickAnswersModal/index.js +++ b/frontend/src/components/QuickAnswersModal/index.js @@ -3,8 +3,8 @@ import React, { useState, useEffect, useRef, useContext } from "react" import * as Yup from "yup" import { Formik, Form, Field } from "formik" import { toast } from "react-toastify" -import openSocket from 'socket.io-client' - +//import openSocket from 'socket.io-client' +import { socket } from "../../services/socket" import { makeStyles, @@ -79,7 +79,7 @@ const QuickAnswersModal = ({ const [quickAnswer, setQuickAnswer] = useState(initialState) const [selectedQueueIds, setSelectedQueueIds] = useState([]) const { user, setting, getSettingValue } = useContext(AuthContext) - const [settings, setSettings] = useState(setting) + const [settings, setSettings] = useState(setting) useEffect(() => { return () => { @@ -92,18 +92,18 @@ const QuickAnswersModal = ({ }, [setting]) useEffect(() => { - + setSelectedQueueIds([]) - if (open && selectedQueueIds.length === 0 && !quickAnswerId) { + if (open && selectedQueueIds.length === 0 && !quickAnswerId) { setSelectedQueueIds(user.queues.map(q => q.id)) } }, [open,]) useEffect(() => { - const socket = openSocket(process.env.REACT_APP_BACKEND_URL) + //const socket = openSocket(process.env.REACT_APP_BACKEND_URL) - socket.on('settings', (data) => { + const onSettingsQuickAnswersModal = (data) => { if (data.action === 'update') { setSettings((prevState) => { const aux = [...prevState] @@ -112,14 +112,16 @@ const QuickAnswersModal = ({ return aux }) } - }) + } + + socket.on('settings', onSettingsQuickAnswersModal) return () => { - socket.disconnect() + socket.off("settings", onSettingsQuickAnswersModal) } }, []) - useEffect(() => { + useEffect(() => { // setSelectedQueueIds([]) @@ -139,7 +141,7 @@ const QuickAnswersModal = ({ if (isMounted.current) { setQuickAnswer(data) - if (data?.queues) { + if (data?.queues) { const quickQueueIds = data.queues?.map((queue) => queue.id) setSelectedQueueIds(quickQueueIds) } diff --git a/frontend/src/components/TransferTicketModal/index.js b/frontend/src/components/TransferTicketModal/index.js index 02acdfc..0b1fb5b 100644 --- a/frontend/src/components/TransferTicketModal/index.js +++ b/frontend/src/components/TransferTicketModal/index.js @@ -1,6 +1,7 @@ import React, { useState, useContext, useMemo, useEffect } from "react" import { useHistory } from "react-router-dom" -import openSocket from "socket.io-client" +//import openSocket from "socket.io-client" +import { socket } from "../../services/socket" import Button from "@material-ui/core/Button" import Dialog from "@material-ui/core/Dialog" @@ -110,9 +111,9 @@ const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => { useEffect(() => { - const socket = openSocket(process.env.REACT_APP_BACKEND_URL) + //const socket = openSocket(process.env.REACT_APP_BACKEND_URL) - socket.on('settings', (data) => { + const onSettingsTransferTicketModal = (data) => { console.log('settings updated ----------------------------xxxxxxxxxxxx') if (data.action === 'update') { @@ -123,10 +124,12 @@ const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => { return aux }) } - }) + } + + socket.on('settings', onSettingsTransferTicketModal) return () => { - socket.disconnect() + socket.off("settings", onSettingsTransferTicketModal) } }, []) @@ -194,7 +197,7 @@ const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => { const { data } = await api.get(`/users/all`, { params: { userId: user.id }, }) - + setUsers(data.users) setQueuesByWhats(data.queues) setQueues(data.queues) @@ -228,7 +231,7 @@ const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => { {i18n.t("transferTicketModal.title")} - + {/* {i18n.t("transferTicketModal.fieldQueueLabel")} */} {'Usuário'} @@ -247,7 +250,7 @@ const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => { ))} - + {i18n.t("transferTicketModal.fieldQueuePlaceholder")} diff --git a/frontend/src/pages/Campaign/index.js b/frontend/src/pages/Campaign/index.js index 0cae436..db78005 100644 --- a/frontend/src/pages/Campaign/index.js +++ b/frontend/src/pages/Campaign/index.js @@ -1,7 +1,8 @@ import React, { useState, useCallback, useEffect, useReducer, useContext } from 'react' -import { toast } from 'react-toastify' +import { toast } from 'react-toastify' -import openSocket from 'socket.io-client' +//import openSocket from 'socket.io-client' +import { socket } from '../../services/socket' import { makeStyles } from '@material-ui/core/styles' import { green } from '@material-ui/core/colors' @@ -13,11 +14,11 @@ import { IconButton, Table, TableHead, - Paper, + Paper, } from '@material-ui/core' import { - Edit, - DeleteOutline, + Edit, + DeleteOutline, // Restore } from '@material-ui/icons' @@ -26,7 +27,7 @@ import MainHeader from '../../components/MainHeader' import MainHeaderButtonsWrapper from '../../components/MainHeaderButtonsWrapper' import Title from '../../components/Title' import TableRowSkeleton from '../../components/TableRowSkeleton' - + import CampaignModal from '../../components/CampaignModal' import ConfirmationModal from '../../components/ConfirmationModal' import QrcodeModal from '../../components/QrcodeModal' @@ -51,7 +52,7 @@ const reducer = (state, action) => { const campaigns = action.payload return [...state, ...campaigns] } - if (action.type === "UPDATE_CAMPAIGNS") { + if (action.type === "UPDATE_CAMPAIGNS") { const campaign = action.payload const campaignIndex = state.findIndex((c) => c.id === campaign.id) @@ -109,7 +110,7 @@ const useStyles = makeStyles((theme) => ({ buttonProgress: { color: green[500], }, -})) +})) const Campaign = () => { //-------- @@ -124,7 +125,7 @@ const Campaign = () => { const [qrModalOpen, setQrModalOpen] = useState(false) const [selectedCampaign, setSelectedCampaign] = useState(null) const [confirmModalOpen, setConfirmModalOpen] = useState(false) - + const [campaigns, dispatch] = useReducer(reducer, []) const [loading, setLoading] = useState(true) @@ -152,7 +153,7 @@ const Campaign = () => { const delayDebounceFn = setTimeout(() => { const fetchContacts = async () => { - try { + try { const { data } = await apiBroker.get('/campaign', { params: { @@ -160,7 +161,7 @@ const Campaign = () => { baseURL: process.env.REACT_APP_BACKEND_URL_PRIVATE, identifier: 'campaign' } - }) + }) dispatch({ type: "LOAD_CAMPAIGNS", payload: data.campaign }) setLoading(false) @@ -174,7 +175,7 @@ const Campaign = () => { }, 500) return () => clearTimeout(delayDebounceFn) }, [user.id]) - + const handleOpenCampaignModal = () => { setSelectedCampaign(null) @@ -184,12 +185,12 @@ const Campaign = () => { const handleCloseCampaignModal = useCallback(() => { setCampaignModalOpen(false) setSelectedCampaign(null) - }, [setSelectedCampaign, setCampaignModalOpen]) + }, [setSelectedCampaign, setCampaignModalOpen]) - const handleStart = async (campaign) => { + const handleStart = async (campaign) => { try { - const { data } = await apiBroker.post(`/campaign/start/${campaign.id}`) + const { data } = await apiBroker.post(`/campaign/start/${campaign.id}`) dispatch({ type: "UPDATE_CAMPAIGNS", payload: data.campaign }) @@ -200,10 +201,10 @@ const Campaign = () => { } } - const handleStop = async (campaign) => { + const handleStop = async (campaign) => { try { - const { data } = await apiBroker.post(`/campaign/stop/${campaign.id}`) + const { data } = await apiBroker.post(`/campaign/stop/${campaign.id}`) dispatch({ type: "UPDATE_CAMPAIGNS", payload: data.campaign }) @@ -245,7 +246,7 @@ const Campaign = () => { setConfirmModalOpen(true) } - const handleSubmitConfirmationModal = async () => { + const handleSubmitConfirmationModal = async () => { if (confirmModalInfo.action === 'delete') { try { @@ -293,13 +294,12 @@ const Campaign = () => { )} ) - } + } useEffect(() => { - const socket = openSocket(process.env.REACT_APP_BACKEND_URL) + //const socket = openSocket(process.env.REACT_APP_BACKEND_URL) - - socket.on("contactsBulkInsertOnQueueStatus", (data) => { + const onContactsBulkCampaing = (data) => { if (data.action === 'update') { if (String(data.insertOnQueue.adminId) === String(user.id)) { @@ -312,19 +312,24 @@ const Campaign = () => { } } - }) + } - socket.on('campaign', (data) => { + socket.on("contactsBulkInsertOnQueueStatus", onContactsBulkCampaing) + + const onCampaignCampaign = (data) => { if (data.action === 'update') { dispatch({ type: "UPDATE_CAMPAIGNS", payload: data.campaign }) } - }) + } + + socket.on('campaign', onCampaignCampaign) + - return () => { - socket.disconnect() + socket.off("campaign", onCampaignCampaign) + socket.off("contactsBulkInsertOnQueueStatus", onContactsBulkCampaing) } }, [user.id]) diff --git a/frontend/src/pages/Connections/index.js b/frontend/src/pages/Connections/index.js index e4055e6..2df93ec 100644 --- a/frontend/src/pages/Connections/index.js +++ b/frontend/src/pages/Connections/index.js @@ -2,7 +2,8 @@ import React, { useState, useCallback, useEffect, useContext } from 'react' import { toast } from 'react-toastify' import { format, parseISO } from 'date-fns' -import openSocket from 'socket.io-client' +//import openSocket from 'socket.io-client' +import { socket } from '../../services/socket' import { makeStyles } from '@material-ui/core/styles' import { green, red, yellow, grey } from '@material-ui/core/colors' @@ -144,7 +145,7 @@ const Connections = () => { const [selectedWhatsApp, setSelectedWhatsApp] = useState(null) const [confirmModalOpen, setConfirmModalOpen] = useState(false) - const [diskSpaceInfo, setDiskSpaceInfo] = useState({}) + const [diskSpaceInfo, setDiskSpaceInfo] = useState({}) const [settings, setSettings] = useState([]) @@ -388,7 +389,7 @@ const Connections = () => { getSettingValue('whatsaAppCloudApi') === 'disabled') && ( - + )} {whatsApp.status === 'OPENING' && !whatsApp.isOfficial && ( @@ -433,7 +434,7 @@ const Connections = () => { try { await api.post(`/restartwhatsappsession/0`, { params: { status: 'status' }, - }) + }) setClicks((buttons) => buttons.map((e) => { @@ -451,15 +452,17 @@ const Connections = () => { }, []) useEffect(() => { - const socket = openSocket(process.env.REACT_APP_BACKEND_URL) + //const socket = openSocket(process.env.REACT_APP_BACKEND_URL) - socket.on('diskSpaceMonit', (data) => { + const onDiskSpaceMonitConnections = (data) => { if (data.action === 'update') { setDiskSpaceInfo(data.diskSpace) } - }) + } - socket.on('settings', (data) => { + socket.on('diskSpaceMonit', onDiskSpaceMonitConnections) + + const onSettingsConnections = (data) => { if (data.action === 'update') { setSettings((prevState) => { const aux = [...prevState] @@ -468,10 +471,13 @@ const Connections = () => { return aux }) } - }) + } + + socket.on('settings', onSettingsConnections) return () => { - socket.disconnect() + socket.off("settings", onSettingsConnections) + socket.off("diskSpaceMonit", onDiskSpaceMonitConnections) } }, []) From dac57f9d487767bc1c3e0faef9fd86caa97b2fd9 Mon Sep 17 00:00:00 2001 From: willian-pessoa Date: Thu, 9 May 2024 15:59:02 -0300 Subject: [PATCH 05/23] refactor: restantes das conexoes para a conexao ws global --- .../components/StatusChatEndModal/index.js | 14 ++-- frontend/src/pages/Contacts/index.js | 22 ++++-- frontend/src/pages/Dashboard/index.js | 57 +++++++------ frontend/src/pages/Position/index.js | 13 +-- frontend/src/pages/Queues/index.js | 24 +++--- frontend/src/pages/QuickAnswers/index.js | 12 +-- frontend/src/pages/Report/index.js | 79 ++++++++++--------- frontend/src/pages/SchedulesReminder/index.js | 20 ++--- frontend/src/pages/Settings/index.js | 15 ++-- frontend/src/pages/StatusChatEnd/index.js | 19 +++-- frontend/src/pages/Users/index.js | 18 +++-- 11 files changed, 169 insertions(+), 124 deletions(-) diff --git a/frontend/src/components/StatusChatEndModal/index.js b/frontend/src/components/StatusChatEndModal/index.js index 1c18884..765aedb 100644 --- a/frontend/src/components/StatusChatEndModal/index.js +++ b/frontend/src/components/StatusChatEndModal/index.js @@ -3,8 +3,8 @@ import React, { useState, useEffect, useRef, useContext } from "react" import * as Yup from "yup" import { Formik, Form, Field } from "formik" import { toast } from "react-toastify" -import openSocket from 'socket.io-client' - +//import openSocket from 'socket.io-client' +import { socket } from "../../services/socket" import { makeStyles, @@ -91,9 +91,9 @@ const StatusChatEndModal = ({ useEffect(() => { - const socket = openSocket(process.env.REACT_APP_BACKEND_URL) + //const socket = openSocket(process.env.REACT_APP_BACKEND_URL) - socket.on('settings', (data) => { + const onSettingsStatusChatEndModal = (data) => { if (data.action === 'update') { setSettings((prevState) => { const aux = [...prevState] @@ -102,10 +102,12 @@ const StatusChatEndModal = ({ return aux }) } - }) + } + + socket.on('settings', onSettingsStatusChatEndModal) return () => { - socket.disconnect() + socket.off("settings", onSettingsStatusChatEndModal) } }, []) diff --git a/frontend/src/pages/Contacts/index.js b/frontend/src/pages/Contacts/index.js index 6a3a616..95e4acb 100644 --- a/frontend/src/pages/Contacts/index.js +++ b/frontend/src/pages/Contacts/index.js @@ -1,5 +1,6 @@ import React, { useState, useEffect, useReducer, useCallback, useContext } from "react" -import openSocket from "socket.io-client" +//import openSocket from "socket.io-client" +import { socket } from "../../services/socket" import { toast } from "react-toastify" import { useHistory } from "react-router-dom" @@ -260,9 +261,9 @@ const Contacts = () => { }, [searchParam, pageNumber]) useEffect(() => { - const socket = openSocket(process.env.REACT_APP_BACKEND_URL) + //const socket = openSocket(process.env.REACT_APP_BACKEND_URL) - socket.on("contactsBulkInsertOnQueueStatus", (data) => { + const onContactsBulkContacts = (data) => { if (data.action === 'update') { if (String(data.insertOnQueue.adminId) === String(user.id)) { @@ -278,9 +279,11 @@ const Contacts = () => { } } - }) + } - socket.on("contact", (data) => { + socket.on("contactsBulkInsertOnQueueStatus", onContactsBulkContacts) + + const onContactContacts = (data) => { if (data.action === "update" || data.action === "create") { dispatch({ type: "UPDATE_CONTACTS", payload: data.contact }) } @@ -288,10 +291,13 @@ const Contacts = () => { if (data.action === "delete") { dispatch({ type: "DELETE_CONTACT", payload: +data.contactId }) } - }) + } + + socket.on("contact", onContactContacts) return () => { - socket.disconnect() + socket.off("contact", onContactContacts) + socket.off("contactsBulkInsertOnQueueStatus", onContactsBulkContacts) } }, [user, history]) @@ -536,7 +542,7 @@ const Contacts = () => { open={contactModalOpen} onClose={handleCloseContactModal} aria-labelledby="form-dialog-title" - contactId={selectedContactId} + contactId={selectedContactId} > { const { data } = await api.get("/reports/user/services", { params: { userId: null, startDate: dateToday, endDate: dateToday, userQueues: selectedQueue }, - }) + }) dispatch({ type: "RESET" }) dispatch({ type: "LOAD_QUERY", payload: data.usersProfile }) @@ -301,7 +302,7 @@ const Dashboard = () => { }) setTicketStatusChatEnd(ticketStatusChatEndData.reportStatusChatEnd) - + } catch (err) { } @@ -356,46 +357,54 @@ const Dashboard = () => { useEffect(() => { - const socket = openSocket(process.env.REACT_APP_BACKEND_URL) + //const socket = openSocket(process.env.REACT_APP_BACKEND_URL) - socket.on("ticketStatus", (data) => { + const onTicketsStatusDashboard = (data) => { if (data.action === "update") { setStatus("") setStatus(data.ticketStatus.status) } - }) + } - socket.on("onlineStatus", (data) => { + socket.on("ticketStatus", onTicketsStatusDashboard) + + const onOnlineStatusDashboard = (data) => { if (data.action === "logout" || data.action === "update") { dispatch({ type: "UPDATE_STATUS_ONLINE", payload: data.userOnlineTime }) } else if (data.action === "delete") { dispatch({ type: "DELETE_USER_STATUS", payload: data.userOnlineTime }) } - }) + } - socket.on("user", (data) => { + socket.on("onlineStatus", onOnlineStatusDashboard) + + const onUserDashboard = (data) => { if (data.action === "delete") { dispatch({ type: "DELETE_USER", payload: +data.userId }) } - }) + } + + socket.on("user", onUserDashboard) return () => { - socket.disconnect() + socket.off("user", onUserDashboard) + socket.off("onlineStatus", onOnlineStatusDashboard) + socket.off("ticketStatus", onTicketsStatusDashboard) } }, []) - + const handleSelectedQueue = useCallback((queueSelected) => { - if(queueSelected !== 'All'){ + if (queueSelected !== 'All') { const queueIndex = user?.queues?.findIndex((q) => q.id === parseInt(queueSelected)); const queueIds = [] queueIds.push(user?.queues[queueIndex]?.id); setSelectedQueue(queueIds); - }else{ + } else { const queueIds = user?.queues?.map((queue) => queue.id); setSelectedQueue(queueIds); } - },[user, setSelectedQueue]) + }, [user, setSelectedQueue]) useEffect(() => { if (ticketStatusChange === "") return @@ -468,14 +477,14 @@ const Dashboard = () => { - { - return { 'value': obj.id, 'label': obj.name } - })} /> + { + return { 'value': obj.id, 'label': obj.name } + })} /> @@ -532,7 +541,7 @@ const Dashboard = () => { - + diff --git a/frontend/src/pages/Position/index.js b/frontend/src/pages/Position/index.js index 5eb50ea..2f53053 100644 --- a/frontend/src/pages/Position/index.js +++ b/frontend/src/pages/Position/index.js @@ -1,5 +1,6 @@ import React, { useState, useContext, useEffect, useReducer } from "react" -import openSocket from "socket.io-client" +//import openSocket from "socket.io-client" +import { socket } from "../../services/socket" import { Button, @@ -125,9 +126,9 @@ const Position = () => { }, [searchParam, pageNumber]) useEffect(() => { - const socket = openSocket(process.env.REACT_APP_BACKEND_URL) + //const socket = openSocket(process.env.REACT_APP_BACKEND_URL) - socket.on("position", (data) => { + const onPositionPosition = (data) => { if (data.action === "update" || data.action === "create") { dispatch({ type: "UPDATE_POSITIONS", payload: data.position }) } @@ -138,10 +139,12 @@ const Position = () => { payload: +data.positionId, }) } - }) + } + + socket.on("position", onPositionPosition) return () => { - socket.disconnect() + socket.off("position", onPositionPosition) } }, []) diff --git a/frontend/src/pages/Queues/index.js b/frontend/src/pages/Queues/index.js index a2ffea1..0ea309d 100644 --- a/frontend/src/pages/Queues/index.js +++ b/frontend/src/pages/Queues/index.js @@ -1,6 +1,7 @@ import React, { useEffect, useReducer, useState, useContext } from 'react' -import openSocket from 'socket.io-client' +//import openSocket from 'socket.io-client' +import { socket } from '../../services/socket' import { Button, @@ -91,7 +92,7 @@ const reducer = (state, action) => { const Queues = () => { const classes = useStyles() - const { user, setting, getSettingValue } = useContext(AuthContext) + const { user, setting, getSettingValue } = useContext(AuthContext) const [queues, dispatch] = useReducer(reducer, []) const [loading, setLoading] = useState(false) @@ -120,12 +121,12 @@ const Queues = () => { setLoading(false) } })() - }, []) + }, []) useEffect(() => { - const socket = openSocket(process.env.REACT_APP_BACKEND_URL) + //const socket = openSocket(process.env.REACT_APP_BACKEND_URL) - socket.on('queue', (data) => { + const onQueueQueues = (data) => { if (data.action === 'update' || data.action === 'create') { dispatch({ type: 'UPDATE_QUEUES', payload: data.queue }) } @@ -133,9 +134,11 @@ const Queues = () => { if (data.action === 'delete') { dispatch({ type: 'DELETE_QUEUE', payload: data.queueId }) } - }) + } - socket.on('settings', (data) => { + socket.on('queue', onQueueQueues) + + const onSettingsQueues = (data) => { if (data.action === 'update') { setSettings((prevState) => { const aux = [...prevState] @@ -144,10 +147,13 @@ const Queues = () => { return aux }) } - }) + } + + socket.on('settings', onSettingsQueues) return () => { - socket.disconnect() + socket.off("settings", onSettingsQueues) + socket.off("queue", onQueueQueues) } }, []) diff --git a/frontend/src/pages/QuickAnswers/index.js b/frontend/src/pages/QuickAnswers/index.js index 5a71233..6c4b5d5 100644 --- a/frontend/src/pages/QuickAnswers/index.js +++ b/frontend/src/pages/QuickAnswers/index.js @@ -1,5 +1,6 @@ import React, { useState, useContext, useEffect, useReducer } from "react" -import openSocket from "socket.io-client" +//import openSocket from "socket.io-client" +import { socket } from "../../services/socket" import { Button, @@ -125,9 +126,9 @@ const QuickAnswers = () => { }, [searchParam, pageNumber]) useEffect(() => { - const socket = openSocket(process.env.REACT_APP_BACKEND_URL) + //const socket = openSocket(process.env.REACT_APP_BACKEND_URL) - socket.on("quickAnswer", (data) => { + const onQuickAnswerQuickAnswers = (data) => { if (data.action === "update" || data.action === "create") { dispatch({ type: "UPDATE_QUICK_ANSWERS", payload: data.quickAnswer }) } @@ -138,10 +139,11 @@ const QuickAnswers = () => { payload: +data.quickAnswerId, }) } - }) + } + socket.on("quickAnswer", onQuickAnswerQuickAnswers) return () => { - socket.disconnect() + socket.off("quickAnswer", onQuickAnswerQuickAnswers) } }, []) diff --git a/frontend/src/pages/Report/index.js b/frontend/src/pages/Report/index.js index 2a94ef3..a1a730b 100644 --- a/frontend/src/pages/Report/index.js +++ b/frontend/src/pages/Report/index.js @@ -18,7 +18,8 @@ import MaterialTable from 'material-table' import LogoutIcon from '@material-ui/icons/CancelOutlined' import apiBroker from "../../services/apiBroker" import fileDownload from 'js-file-download' -import openSocket from "socket.io-client" +//import openSocket from "socket.io-client" +import { socket } from "../../services/socket" import { i18n } from "../../translate/i18n" import Switch from '@mui/material/Switch' @@ -239,7 +240,7 @@ let columnsData = [ { title: `Espera`, field: 'waiting_time' }, { title: `Mensagens`, field: 'messagesToFilter', searchable: true, hidden: true }, { title: `Link`, field: 'link', searchable: false, hidden: true, export: true }, -] +] let columnsDataSuper = [ { title: `Tipo`, field: 'isRemote' }, @@ -381,10 +382,10 @@ const Report = () => { const tickets = data.tickets.map(ticket => { ticket.isRemote = ticket.isRemote ? 'Remoto' : 'Comum'; return ({ - ...ticket, - messagesToFilter: ticket.messages.map(message => message.body).join(' '), - link: `${process.env.REACT_APP_FRONTEND_URL}/tickets/${ticket.id}` - }) + ...ticket, + messagesToFilter: ticket.messages.map(message => message.body).join(' '), + link: `${process.env.REACT_APP_FRONTEND_URL}/tickets/${ticket.id}` + }) }) dispatchQ({ type: "LOAD_QUERY", payload: tickets }) setHasMore(data.hasMore) @@ -591,9 +592,9 @@ const Report = () => { useEffect(() => { - const socket = openSocket(process.env.REACT_APP_BACKEND_URL) + //const socket = openSocket(process.env.REACT_APP_BACKEND_URL) - socket.on("queryOnQueueStatus", (data) => { + const onQueryOnQueueStatusReport = (data) => { if (data.action === 'update') { if (String(data.queryOnQueue.adminId) === String(userA.id)) { @@ -604,35 +605,39 @@ const Report = () => { } } - }) + } + + socket.on("queryOnQueueStatus", onQueryOnQueueStatusReport) + + const onOnlineStatusReport = (data) => { + + let date = new Date().toLocaleDateString('pt-BR').split('/') + let dateToday = `${date[2]}-${date[1]}-${date[0]}` + + if (data.action === "logout" || (data.action === "update" && + ((`${startDate}` === `${endDate}`) && (`${endDate}` === `${dateToday}`) && (`${startDate}` === `${dateToday}`)))) { + + dispatchQ({ type: "UPDATE_STATUS_ONLINE", payload: data.userOnlineTime }) + + } + else if (data.action === "delete") { + dispatchQ({ type: "DELETE_USER_STATUS", payload: data.userOnlineTime }) + } + + } + + const onUserReport = (data) => { + + if (data.action === "delete") { + dispatch({ type: "DELETE_USER", payload: +data.userId }) + } + } if (reportOption === '2') { + socket.on("onlineStatus", onOnlineStatusReport) - socket.on("onlineStatus", (data) => { - - let date = new Date().toLocaleDateString('pt-BR').split('/') - let dateToday = `${date[2]}-${date[1]}-${date[0]}` - - if (data.action === "logout" || (data.action === "update" && - ((`${startDate}` === `${endDate}`) && (`${endDate}` === `${dateToday}`) && (`${startDate}` === `${dateToday}`)))) { - - dispatchQ({ type: "UPDATE_STATUS_ONLINE", payload: data.userOnlineTime }) - - } - else if (data.action === "delete") { - dispatchQ({ type: "DELETE_USER_STATUS", payload: data.userOnlineTime }) - } - - }) - - socket.on("user", (data) => { - - if (data.action === "delete") { - dispatch({ type: "DELETE_USER", payload: +data.userId }) - } - }) - + socket.on("user", onUserReport) } else if (reportOption === "1") { @@ -641,7 +646,9 @@ const Report = () => { } return () => { - socket.disconnect() + socket.off("onlineStatus", onOnlineStatusReport) + socket.off("user", onUserReport) + socket.off("queryOnQueueStatus", onQueryOnQueueStatusReport) } @@ -687,7 +694,7 @@ const Report = () => { const renderSwitch = (param) => { - if(userA.profile !== 'supervisor'){ + if (userA.profile !== 'supervisor') { switch (param) { case 'empty': return ( @@ -880,7 +887,7 @@ const Report = () => { <> { useEffect(() => { - const socket = openSocket(process.env.REACT_APP_BACKEND_URL) - - socket.on("schedulingNotify", (data) => { - + //const socket = openSocket(process.env.REACT_APP_BACKEND_URL) + const onSchedulingNotifySchedulesRemider = (data) => { setLoading(true) @@ -228,10 +226,12 @@ const SchedulesReminder = () => { setLoading(false) - }) + } + + socket.on("schedulingNotify", onSchedulingNotifySchedulesRemider) return () => { - socket.disconnect() + socket.off("schedulingNotify", onSchedulingNotifySchedulesRemider) } }, []) @@ -300,9 +300,9 @@ const SchedulesReminder = () => { - useEffect(() => { + useEffect(() => { - if (!loading) { + if (!loading) { setData(query.map(({ scheduleReminder, ...others }) => ( { diff --git a/frontend/src/pages/Settings/index.js b/frontend/src/pages/Settings/index.js index 5dc6bbc..d363c9d 100644 --- a/frontend/src/pages/Settings/index.js +++ b/frontend/src/pages/Settings/index.js @@ -1,5 +1,6 @@ import React, { useState, useEffect, useContext } from 'react' -import openSocket from 'socket.io-client' +//import openSocket from 'socket.io-client' +import { socket } from '../../services/socket.js' import { makeStyles } from '@material-ui/core/styles' import Paper from '@material-ui/core/Paper' @@ -124,9 +125,9 @@ const Settings = () => { useEffect(() => { - const socket = openSocket(process.env.REACT_APP_BACKEND_URL) + //const socket = openSocket(process.env.REACT_APP_BACKEND_URL) - socket.on('settings', (data) => { + const onSettingsSettings = (data) => { console.log('settings updated ----------------------------') if (data.action === 'update') { @@ -137,10 +138,12 @@ const Settings = () => { return aux }) } - }) + } + + socket.on('settings', onSettingsSettings) return () => { - socket.disconnect() + socket.off("settings", onSettingsSettings) } }, []) @@ -641,7 +644,7 @@ const Settings = () => { -
+ )} /> diff --git a/frontend/src/pages/StatusChatEnd/index.js b/frontend/src/pages/StatusChatEnd/index.js index c8de207..6a0f621 100644 --- a/frontend/src/pages/StatusChatEnd/index.js +++ b/frontend/src/pages/StatusChatEnd/index.js @@ -1,5 +1,6 @@ import React, { useState, useContext, useEffect, useReducer } from "react" -import openSocket from "socket.io-client" +//import openSocket from "socket.io-client" +import { socket } from "../../services/socket" import { Button, @@ -115,7 +116,7 @@ const StatusChatEnd = () => { const { data } = await api.get("/statusChatEnd", { params: { searchParam, pageNumber }, }) - + setChecked(data?.statusChatEnd?.map(s => s.isDefault ? true : false)) dispatch({ type: "LOAD_STATUS_CHAT_END", payload: data.statusChatEnd }) @@ -131,9 +132,9 @@ const StatusChatEnd = () => { }, [searchParam, pageNumber]) useEffect(() => { - const socket = openSocket(process.env.REACT_APP_BACKEND_URL) + //const socket = openSocket(process.env.REACT_APP_BACKEND_URL) - socket.on("statusChatEnd", (data) => { + const onStatusChatEndStatusChatEnd = (data) => { if (data.action === "update" || data.action === "create") { dispatch({ type: "UPDATE_STATUS_CHAT_END", payload: data.statusChatEnd }) } @@ -144,10 +145,12 @@ const StatusChatEnd = () => { payload: +data.statusChatEndId, }) } - }) + } + + socket.on("statusChatEnd", onStatusChatEndStatusChatEnd) return () => { - socket.disconnect() + socket.off("statusChatEnd", onStatusChatEndStatusChatEnd) } }, []) @@ -187,14 +190,14 @@ const StatusChatEnd = () => { } const handleChange = async (event, statusChatEnd, index) => { - + const newChecked = new Array(statusChatEnds.length).fill(false) newChecked[index] = event.target.checked setChecked(newChecked) try { const { id } = statusChatEnd - await api.put(`/statusChatEnd/${id}`, { isDefault: event.target.checked }) + await api.put(`/statusChatEnd/${id}`, { isDefault: event.target.checked }) toast.success("Status de encerramento padrão salvo com sucesso") } catch (error) { diff --git a/frontend/src/pages/Users/index.js b/frontend/src/pages/Users/index.js index c6c3af2..4a090e7 100644 --- a/frontend/src/pages/Users/index.js +++ b/frontend/src/pages/Users/index.js @@ -1,6 +1,7 @@ import React, { useState, useEffect, useReducer, useContext } from "react" import { toast } from "react-toastify" -import openSocket from "socket.io-client" +//import openSocket from "socket.io-client" +import { socket } from "../../services/socket" import { makeStyles } from "@material-ui/core/styles" import Paper from "@material-ui/core/Paper" @@ -165,9 +166,9 @@ const Users = () => { useEffect(() => { - const socket = openSocket(process.env.REACT_APP_BACKEND_URL) + //const socket = openSocket(process.env.REACT_APP_BACKEND_URL) - socket.on("user", (data) => { + const onUserUsers = (data) => { if (data.action === "update" || data.action === "create") { dispatch({ type: "UPDATE_USERS", payload: data.user }) } @@ -175,10 +176,11 @@ const Users = () => { if (data.action === "delete") { dispatch({ type: "DELETE_USER", payload: +data.userId }) } - }) + } + socket.on("user", onUserUsers) - socket.on('settings', (data) => { + const onSettingsUsers = (data) => { if (data.action === 'update') { setSettings((prevState) => { const aux = [...prevState] @@ -187,10 +189,12 @@ const Users = () => { return aux }) } - }) + } + socket.on('settings', onSettingsUsers) return () => { - socket.disconnect() + socket.off("settings", onSettingsUsers) + socket.off("user", onUserUsers) } }, []) From eb1d0f23036d92610f4479ee088a3589e2bd6736 Mon Sep 17 00:00:00 2001 From: willian-pessoa Date: Thu, 9 May 2024 16:01:21 -0300 Subject: [PATCH 06/23] feat: verificar ticket id antes de atualizar lista de msgs --- frontend/src/components/MessagesList/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/MessagesList/index.js b/frontend/src/components/MessagesList/index.js index 438b7ad..b5c071b 100644 --- a/frontend/src/components/MessagesList/index.js +++ b/frontend/src/components/MessagesList/index.js @@ -452,14 +452,14 @@ const MessagesList = ({ ticketId, isGroup }) => { onAppMessageMessagesList = (data) => { - if (data.action === "create") { + if (data.action === "create" && data.ticket.id === ticketId) { dispatch({ type: "ADD_MESSAGE", payload: data.message }) scrollToBottom() } - if (data.action === "update") { + if (data.action === "update" && data.ticket.id === ticketId) { dispatch({ type: "UPDATE_MESSAGE", payload: data.message }) } } From 62f137d8849dfe41e719f5de51c6bf4034e749a1 Mon Sep 17 00:00:00 2001 From: adriano Date: Mon, 20 May 2024 10:00:45 -0300 Subject: [PATCH 07/23] feat: load balance --- backend/package.json | 4 +- .../helpers/SchedulingNotifySendMessage.ts | 20 ++++----- backend/src/libs/socket.ts | 44 +++++++++++++++---- frontend/package.json | 2 +- frontend/server.js | 2 +- frontend/src/components/MessagesList/index.js | 8 ++-- frontend/src/services/api.js | 2 +- frontend/src/services/socket.js | 9 +++- 8 files changed, 63 insertions(+), 28 deletions(-) diff --git a/backend/package.json b/backend/package.json index 1e5bd13..d8bffa5 100644 --- a/backend/package.json +++ b/backend/package.json @@ -17,6 +17,7 @@ "license": "MIT", "dependencies": { "@sentry/node": "^5.29.2", + "@socket.io/redis-adapter": "^7.2.0", "@types/fluent-ffmpeg": "^2.1.21", "@types/pino": "^6.3.4", "axios": "^1.2.3", @@ -41,12 +42,13 @@ "pino": "^6.9.0", "pino-pretty": "^9.1.1", "qrcode-terminal": "^0.12.0", + "redis": "^4.6.13", "reflect-metadata": "^0.1.13", "sequelize": "^5.22.3", "sequelize-cli": "^5.5.1", "sequelize-typescript": "^1.1.0", "sharp": "^0.32.5", - "socket.io": "^3.0.5", + "socket.io": "^4.7.5", "socket.io-client": "^4.5.4", "uuid": "^8.3.2", "whatsapp-web.js": "github:pedroslopez/whatsapp-web.js", diff --git a/backend/src/helpers/SchedulingNotifySendMessage.ts b/backend/src/helpers/SchedulingNotifySendMessage.ts index 01f1c0b..d75a903 100644 --- a/backend/src/helpers/SchedulingNotifySendMessage.ts +++ b/backend/src/helpers/SchedulingNotifySendMessage.ts @@ -104,16 +104,16 @@ const monitor = async () => { stdout = stdout[1].trim().split(/\s+/); // DISK SPACE MONITORING - const io = getIO(); - io.emit("diskSpaceMonit", { - action: "update", - diskSpace: { - size: stdout[1], - used: stdout[2], - available: stdout[3], - use: stdout[4] - } - }); + // const io = getIO(); + // io.emit("diskSpaceMonit", { + // action: "update", + // diskSpace: { + // size: stdout[1], + // used: stdout[2], + // available: stdout[3], + // use: stdout[4] + // } + // }); let data: any = {}; diff --git a/backend/src/libs/socket.ts b/backend/src/libs/socket.ts index 65382d6..8412760 100644 --- a/backend/src/libs/socket.ts +++ b/backend/src/libs/socket.ts @@ -3,6 +3,9 @@ import { Server } from "http"; import AppError from "../errors/AppError"; import { logger } from "../utils/logger"; +import { createAdapter } from "@socket.io/redis-adapter"; +import { createClient } from 'redis'; + import { v4 as uuidv4 } from "uuid"; import ListUserParamiterService from "../services/UserServices/ListUserParamiterService"; import { @@ -27,6 +30,7 @@ import { } from "../services/WbotServices/wbotMessageListener"; import { join } from "path"; import Whatsapp from "../models/Whatsapp"; +import { get } from "../helpers/RedisClient" let count: number = 0; let listOnline: any[] = []; @@ -42,16 +46,32 @@ let dateTime = splitDateTime( new Date(format(new Date(), "yyyy-MM-dd HH:mm:ss", { locale: ptBR })) ); -export const initIO = (httpServer: Server): SocketIO => { + +const pubClient = createClient({ url: 'redis://172.31.187.29:6379' }); +const subClient = pubClient.duplicate(); + + +pubClient.connect().catch(console.error); +subClient.connect().catch(console.error); + + +export const initIO = (httpServer: Server): SocketIO => { + io = new SocketIO(httpServer, { cors: { - origin: process.env.FRONTEND_URL + origin: "*", + allowedHeaders: ["my-custom-header"], + credentials: true }, - maxHttpBufferSize: 1e8 - }); + maxHttpBufferSize: 1e8, + pingInterval: 25000, + pingTimeout: 60000, + adapter: createAdapter(pubClient, subClient) + }); + io.on("connection", socket => { - logger.info("Client Connected"); + logger.info("Client Connected"); socket.on("joinWhatsSession", (whatsappId: string) => { logger.info(`A client joined a joinWhatsSession channel: ${whatsappId}`); @@ -107,6 +127,7 @@ export const initIO = (httpServer: Server): SocketIO => { socket.on("online", (userId: any) => { // console.log('userId: ', userId) + return obj.uuid = uuidv4(); if (userId.logoutUserId) { @@ -233,13 +254,18 @@ export const initIO = (httpServer: Server): SocketIO => { if (rooms && rooms.size == 2 && ![...rooms][1].startsWith("session_")) return; - let whatsappIds: any = await Whatsapp.findAll({ - attributes: ["id"], - raw: true + let whatsappIds = await get({ + key: "whatsapp:*", + parse: true }); + // let whatsappIds: any = await Whatsapp.findAll({ + // attributes: ["id"], + // raw: true + // }); + if (whatsappIds && whatsappIds.length > 0) { - whatsappIds = whatsappIds.map((e: any) => `${e.id}`); + // whatsappIds = whatsappIds.map((e: any) => `${e.id}`); console.log( "whatsappIds whatsappIds whatsappIds whatsappIds whatsappIds: ", diff --git a/frontend/package.json b/frontend/package.json index 681cd4b..d30e4f4 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -43,7 +43,7 @@ "yup": "^0.32.8" }, "scripts": { - "start": "react-scripts start", + "start": "PORT=3331 react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" diff --git a/frontend/server.js b/frontend/server.js index a05ba32..ff983c1 100644 --- a/frontend/server.js +++ b/frontend/server.js @@ -6,4 +6,4 @@ app.use(express.static(path.join(__dirname, "build"))); app.get("/*", function (req, res) { res.sendFile(path.join(__dirname, "build", "index.html")); }); -app.listen(3333); +app.listen(3331); diff --git a/frontend/src/components/MessagesList/index.js b/frontend/src/components/MessagesList/index.js index b5c071b..8773cc1 100644 --- a/frontend/src/components/MessagesList/index.js +++ b/frontend/src/components/MessagesList/index.js @@ -450,16 +450,16 @@ const MessagesList = ({ ticketId, isGroup }) => { socket.on("connect", onConnectMessagesList) - onAppMessageMessagesList = (data) => { + const onAppMessageMessagesList = (data) => { - if (data.action === "create" && data.ticket.id === ticketId) { + if (data.action === "create") { dispatch({ type: "ADD_MESSAGE", payload: data.message }) scrollToBottom() } - if (data.action === "update" && data.ticket.id === ticketId) { + if (data.action === "update") { dispatch({ type: "UPDATE_MESSAGE", payload: data.message }) } } @@ -960,4 +960,4 @@ const MessagesList = ({ ticketId, isGroup }) => { ) } -export default MessagesList \ No newline at end of file +export default MessagesList diff --git a/frontend/src/services/api.js b/frontend/src/services/api.js index 209fc12..116eac5 100644 --- a/frontend/src/services/api.js +++ b/frontend/src/services/api.js @@ -1,7 +1,7 @@ import axios from "axios"; const api = axios.create({ - baseURL: process.env.REACT_APP_BACKEND_URL, + baseURL: process.env.REACT_APP_BACKEND_URL + "/api", withCredentials: true, }); diff --git a/frontend/src/services/socket.js b/frontend/src/services/socket.js index a458f57..e0b4950 100644 --- a/frontend/src/services/socket.js +++ b/frontend/src/services/socket.js @@ -3,4 +3,11 @@ import { io } from 'socket.io-client'; // "undefined" means the URL will be computed from the `window.location` object const URL = process.env.REACT_APP_BACKEND_URL -export const socket = io(URL); \ No newline at end of file +export const socket = io(URL, { + path: "/api-ws/socketio", + withCredentials: true, + extraHeaders: { + "my-custom-header": "abcd" + }, + // transports: ['websocket', 'polling'] +}); \ No newline at end of file From 7bb73cfa19d67bbf36f1fe4064e20c047564bbef Mon Sep 17 00:00:00 2001 From: adriano Date: Mon, 20 May 2024 17:24:06 -0300 Subject: [PATCH 08/23] fix: bugs de atualizacao dos tickets tempo real --- frontend/src/components/MessagesList/index.js | 5 +++-- frontend/src/components/Ticket/index.js | 2 +- frontend/src/components/TicketsList/index.js | 1 + frontend/src/components/TransferTicketModal/index.js | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/MessagesList/index.js b/frontend/src/components/MessagesList/index.js index 8773cc1..b351237 100644 --- a/frontend/src/components/MessagesList/index.js +++ b/frontend/src/components/MessagesList/index.js @@ -452,14 +452,14 @@ const MessagesList = ({ ticketId, isGroup }) => { const onAppMessageMessagesList = (data) => { - if (data.action === "create") { + if (data.action === "create" && data.ticket.id == ticketId) { dispatch({ type: "ADD_MESSAGE", payload: data.message }) scrollToBottom() } - if (data.action === "update") { + if (data.action === "update" && data.ticket.id == ticketId) { dispatch({ type: "UPDATE_MESSAGE", payload: data.message }) } } @@ -467,6 +467,7 @@ const MessagesList = ({ ticketId, isGroup }) => { socket.on("appMessage", onAppMessageMessagesList) return () => { + socket.emit("leaveChatBox", ticketId) socket.off("connect", onConnectMessagesList) socket.off("appMessage", onAppMessageMessagesList) } diff --git a/frontend/src/components/Ticket/index.js b/frontend/src/components/Ticket/index.js index cd6cb41..4ef036f 100644 --- a/frontend/src/components/Ticket/index.js +++ b/frontend/src/components/Ticket/index.js @@ -143,7 +143,7 @@ const Ticket = () => { socket.on("connect", onConnectTicket) const onTicketTicket = (data) => { - if (data.action === "update") { + if (data.action === "update" && data.ticket.id == ticketId) { setTicket(data.ticket) } diff --git a/frontend/src/components/TicketsList/index.js b/frontend/src/components/TicketsList/index.js index 36dee0a..73b0f1e 100644 --- a/frontend/src/components/TicketsList/index.js +++ b/frontend/src/components/TicketsList/index.js @@ -246,6 +246,7 @@ const TicketsList = (props) => { //const socket = openSocket(process.env.REACT_APP_BACKEND_URL) const shouldUpdateTicket = ticket => + (status === ticket.status) && (!ticket.userId || ticket.userId === user?.id || showAll) && (!ticket.queueId || selectedQueueIds.indexOf(ticket.queueId) > -1) diff --git a/frontend/src/components/TransferTicketModal/index.js b/frontend/src/components/TransferTicketModal/index.js index 0b1fb5b..5f2671e 100644 --- a/frontend/src/components/TransferTicketModal/index.js +++ b/frontend/src/components/TransferTicketModal/index.js @@ -262,7 +262,7 @@ const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => { required >   - {queues.map((queue) => ( + {queues?.map((queue) => ( Date: Tue, 21 May 2024 10:15:59 -0300 Subject: [PATCH 09/23] fix: getSettingValue quebrando a app --- frontend/src/pages/Settings/index.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/src/pages/Settings/index.js b/frontend/src/pages/Settings/index.js index d363c9d..6490aaa 100644 --- a/frontend/src/pages/Settings/index.js +++ b/frontend/src/pages/Settings/index.js @@ -182,7 +182,11 @@ const Settings = () => { } const getSettingValue = (key, _obj = false) => { - const { value, obj } = settings.find((s) => s.key === key) + //const { value, obj } = settings.find((s) => s.key === key) + const setting = settings.find((s) => s.key === key) + + const value = setting?.value || "" + const obj = setting?.obj || null if (_obj) return obj From fce5554681e3f7d3cfed73235fef07af7d3d9e5c Mon Sep 17 00:00:00 2001 From: adriano Date: Wed, 22 May 2024 09:51:10 -0300 Subject: [PATCH 10/23] fix: update message ack --- frontend/src/components/MessagesList/index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/MessagesList/index.js b/frontend/src/components/MessagesList/index.js index b351237..60b7a71 100644 --- a/frontend/src/components/MessagesList/index.js +++ b/frontend/src/components/MessagesList/index.js @@ -451,15 +451,16 @@ const MessagesList = ({ ticketId, isGroup }) => { socket.on("connect", onConnectMessagesList) const onAppMessageMessagesList = (data) => { + if (+data.message.ticketId !== +ticketId) return - if (data.action === "create" && data.ticket.id == ticketId) { + if (data.action === "create") { dispatch({ type: "ADD_MESSAGE", payload: data.message }) scrollToBottom() } - if (data.action === "update" && data.ticket.id == ticketId) { + if (data.action === "update") { dispatch({ type: "UPDATE_MESSAGE", payload: data.message }) } } From 435a577bedabba86cda50b31d1230a17208d4fd1 Mon Sep 17 00:00:00 2001 From: adriano Date: Wed, 22 May 2024 12:51:11 -0300 Subject: [PATCH 11/23] fix: listener para ticket deletado --- frontend/src/components/Ticket/index.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/Ticket/index.js b/frontend/src/components/Ticket/index.js index 4ef036f..fd7efce 100644 --- a/frontend/src/components/Ticket/index.js +++ b/frontend/src/components/Ticket/index.js @@ -143,11 +143,15 @@ const Ticket = () => { socket.on("connect", onConnectTicket) const onTicketTicket = (data) => { - if (data.action === "update" && data.ticket.id == ticketId) { + const isSameTicket = +data?.ticket?.id === +ticketId || +data.ticketId === +ticketId + if (!isSameTicket) return + + if (data.action === "update") { setTicket(data.ticket) } - if (data.action === "delete") { + if (data.action === "deleteForever") { + console.log('delete forever') toast.success("Ticket deleted sucessfully.") history.push("/tickets") } From 83d197f2407600c13e59cc43adfa49ecaa99b9d8 Mon Sep 17 00:00:00 2001 From: adriano Date: Thu, 23 May 2024 17:39:42 -0300 Subject: [PATCH 12/23] feat: remoteTickesControll listeners --- frontend/src/components/TicketListItem/index.js | 8 +++++--- frontend/src/components/TicketsList/index.js | 9 +++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/TicketListItem/index.js b/frontend/src/components/TicketListItem/index.js index 931be34..38c00a3 100644 --- a/frontend/src/components/TicketListItem/index.js +++ b/frontend/src/components/TicketListItem/index.js @@ -154,12 +154,14 @@ const TicketListItem = ({ ticket, remoteTicketsControll, settings }) => { useEffect(() => { //const socket = openSocket(process.env.REACT_APP_BACKEND_URL) - socket.on('remoteTickesControll', (data) => { + const onRemoteTickesControllTicketListItem = (data) => { console.log('REMOTE TICKETS CONTROLL UPDATE2: ', data.tickets) if (data.action === 'update') { setRemoteTicketsControll(data.tickets) } - }) + } + + socket.on('remoteTickesControll', onRemoteTickesControllTicketListItem) const onSettingsTicketListItem = (data) => { if (data.action === 'update') { @@ -175,7 +177,7 @@ const TicketListItem = ({ ticket, remoteTicketsControll, settings }) => { socket.on('settings', onSettingsTicketListItem) return () => { - socket.removeAllListeners('remoteTickesControll'); + socket.off('remoteTickesControll', onRemoteTickesControllTicketListItem); socket.off('settings', onSettingsTicketListItem); } }, []) diff --git a/frontend/src/components/TicketsList/index.js b/frontend/src/components/TicketsList/index.js index 73b0f1e..20ebe2f 100644 --- a/frontend/src/components/TicketsList/index.js +++ b/frontend/src/components/TicketsList/index.js @@ -323,13 +323,14 @@ const TicketsList = (props) => { } }) - - socket.on('remoteTickesControll', (data) => { + const onRemoteTickesControllTicketList = (data) => { console.log('REMOTE TICKETS CONTROLL UPDATE 1: ', data.tickets) if (data.action === 'update') { setRemoteTicketsControll(data.tickets) } - }) + } + + socket.on('remoteTickesControll', onRemoteTickesControllTicketList) const onSettingsTicketList = (data) => { if (data.action === 'update') { @@ -350,7 +351,7 @@ const TicketsList = (props) => { socket.removeAllListeners("contact") socket.off('connect', onConnectTicketList); socket.off('settings', onSettingsTicketList); - socket.removeAllListeners('remoteTickesControll'); + socket.off('remoteTickesControll', onRemoteTickesControllTicketList); } }, [status, showAll, user, selectedQueueIds, tab]) From e30573519d6925bfd66d40300ab862bdefb19985 Mon Sep 17 00:00:00 2001 From: gustavo-gsp Date: Tue, 25 Jun 2024 10:45:46 -0300 Subject: [PATCH 13/23] fix: resolve issues with WhatsApp creation and editing, message input, and ControlByNumber errors Details: - Fixed issue where the 'number' field was not being saved during WhatsApp creation and editing. - Resolved problem where text in the message input was being cleared upon receiving a new message. - Addressed errors in ControlByNumber when ticketId was not found. --- backend/src/controllers/WhatsAppController.ts | 12 +++++--- backend/src/helpers/controllByNumber.ts | 29 ++++++++++--------- frontend/src/components/MessageInput/index.js | 2 +- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/backend/src/controllers/WhatsAppController.ts b/backend/src/controllers/WhatsAppController.ts index 0158748..1a82021 100644 --- a/backend/src/controllers/WhatsAppController.ts +++ b/backend/src/controllers/WhatsAppController.ts @@ -377,9 +377,11 @@ export const store = async (req: Request, res: Response): Promise => { } else if (!isOfficial) { phoneNumberId = ""; wabaId = ""; - number = ""; + //number = ""; + } + if(!number){ + number = getNumberFromName(name) } - let invalidPhoneName = validatePhoneName(name); if (invalidPhoneName) { @@ -479,9 +481,11 @@ export const update = async ( } else if (!isOfficial) { whatsappData.phoneNumberId = ""; whatsappData.wabaId = ""; - whatsappData.number = ""; + //whatsappData.number = ""; + } + if(!whatsappData?.number){ + whatsappData.number = getNumberFromName(whatsappData.name) } - const { whatsapp, oldDefaultWhatsapp } = await UpdateWhatsAppService({ whatsappData, whatsappId diff --git a/backend/src/helpers/controllByNumber.ts b/backend/src/helpers/controllByNumber.ts index e202f6f..6ffad64 100644 --- a/backend/src/helpers/controllByNumber.ts +++ b/backend/src/helpers/controllByNumber.ts @@ -13,43 +13,44 @@ async function controllByNumber() { let controll: any[] = []; for (const ticket of tickets) { - let match = ticket.match(/"whatsappId":(\d+)/); + let match = ticket?.match(/"whatsappId":(\d+)/); let whatsappId = match ? match[1] : null; const whatsapp = await get({ key: `whatsapp:${whatsappId}` }); - match = whatsapp.match(/"number":"(\d+)"/); + match = whatsapp?.match(/"number":"(\d+)"/); let number = match ? match[1] : null; - match = ticket.match(/"id":(\d+)/); + match = ticket?.match(/"id":(\d+)/); let ticketId = match ? match[1] : null; number = JSON.parse(number); ticketId = JSON.parse(ticketId); - const index = controll.findIndex((c: any) => c.number == number); + const index = controll?.findIndex((c: any) => c.number == number); if (index == -1) { - controll.push({ ticketId, number }); + controll?.push({ ticketId, number }); } } - const ticketIds = controll.map((c: any) => c.ticketId); + const ticketIds = controll?.map((c: any) => c.ticketId); - console.log("=======> ticketIds: ", ticketIds); + //console.log("=======> ticketIds: ", ticketIds); for (const ticketId of ticketIds) { const ticket: any = await Ticket.findByPk(ticketId); + if(ticket){ + const { status } = ticket; - const { status } = ticket; - - if (status == "pending") { - await UpdateTicketService({ - ticketData: { statusChatEnd: uuidv4() }, - ticketId: ticket.id - }); + if (status && status == "pending") { + await UpdateTicketService({ + ticketData: { statusChatEnd: uuidv4() }, + ticketId: ticket.id + }); + } } } diff --git a/frontend/src/components/MessageInput/index.js b/frontend/src/components/MessageInput/index.js index 9f0b895..f20b25a 100644 --- a/frontend/src/components/MessageInput/index.js +++ b/frontend/src/components/MessageInput/index.js @@ -247,7 +247,7 @@ const MessageInput = ({ ticketStatus, ticketLastMessage, ticketIsRemote }) => { setInputMessage(ticketLastMessage) } else { - setInputMessage("") + //setInputMessage("") } }, [countTicketMsg, ticketIsRemote, ticketLastMessage]) From 2bb5db92d7c652a3d9b5bc7e98dd06f7458f5baf Mon Sep 17 00:00:00 2001 From: gustavo-gsp Date: Thu, 27 Jun 2024 14:10:26 -0300 Subject: [PATCH 14/23] fix: resolve issue with blocking audio and video without the option being active Details: - Fixed the problem where audio and video were being blocked even when the option was not active. --- .../src/services/WbotServices/wbotMessageListener.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/backend/src/services/WbotServices/wbotMessageListener.ts b/backend/src/services/WbotServices/wbotMessageListener.ts index db8604a..53b50e2 100644 --- a/backend/src/services/WbotServices/wbotMessageListener.ts +++ b/backend/src/services/WbotServices/wbotMessageListener.ts @@ -184,12 +184,10 @@ const verifyMediaMessage = async ( phoneNumberId: msg?.phoneNumberId, fromAgent: false }; - if ( - messageData.mediaType === "video" || - (messageData.mediaType === "audio" && - getSettingValue("blockAudioVideoMedia")?.value === "enabled") - ) { - mediaAuthorized = false; + if(getSettingValue('blockAudioVideoMedia')?.value === 'enabled'){ + if( messageData.mediaType === 'video' || messageData.mediaType === 'audio' ){ + mediaAuthorized = false; + } } if (msg?.fromMe) { messageData = { ...messageData, fromAgent: true }; From c39cae9f81f084b04602671ea4e55723e1ec9676 Mon Sep 17 00:00:00 2001 From: adriano Date: Thu, 25 Jul 2024 11:05:39 -0500 Subject: [PATCH 15/23] fix(i18n): add missing translations in the interface --- .../ChatEnd/TimerPickerSelect/index.js | 4 +- frontend/src/components/ConfigModal/index.js | 39 ++++----- .../src/components/DashboardUser/CardUser.jsx | 10 ++- .../DatePicker2/index.js | 4 +- .../TimerPickerSelect2/index.js | 4 +- .../src/components/PositionModal/index.js | 4 +- .../src/components/Report/DatePicker/index.js | 4 +- frontend/src/components/Report/Modal/index.js | 2 +- frontend/src/components/ReportModal/index.js | 7 +- frontend/src/components/UserModal/index.js | 4 +- frontend/src/layout/MainListItems.js | 4 +- frontend/src/pages/Dashboard/PieChart.js | 4 +- frontend/src/pages/Dashboard/index.js | 10 +-- frontend/src/pages/Report/index.js | 76 +++++++++--------- frontend/src/pages/StatusChatEnd/index.js | 10 +-- frontend/src/translate/languages/en.js | 80 +++++++++++++++---- frontend/src/translate/languages/es.js | 73 ++++++++++++++--- frontend/src/translate/languages/pt.js | 61 ++++++++++++-- 18 files changed, 283 insertions(+), 117 deletions(-) diff --git a/frontend/src/components/ChatEnd/TimerPickerSelect/index.js b/frontend/src/components/ChatEnd/TimerPickerSelect/index.js index b49ccf7..b642246 100644 --- a/frontend/src/components/ChatEnd/TimerPickerSelect/index.js +++ b/frontend/src/components/ChatEnd/TimerPickerSelect/index.js @@ -45,7 +45,7 @@ import { import ptBrLocale from "date-fns/locale/pt-BR"; - +import esLocale from 'date-fns/locale/es'; const ResponsiveTimePickers = (props) => { @@ -63,7 +63,7 @@ const ResponsiveTimePickers = (props) => { - + { }} > {({ values, touched, errors, isSubmitting }) => ( - +
@@ -299,7 +302,7 @@ const ConfigModal = ({ open, onClose, change }) => { { { checked={values.businessTimeEnable} /> } - label={'Ativar/Desativar'} /> + label={i18n.t('configModal.titles.enableDisable')} />
{ { { checked={values.businessTimeEnableSaturday} /> } - label={'Ativar/Desativar'} /> + label={i18n.t('configModal.titles.enableDisable')} />
{
{/* SABADO FIM */}
- + {/* Saturday and Sunday date */}
@@ -430,13 +433,13 @@ const ConfigModal = ({ open, onClose, change }) => { checked={values.enableWeekendMessage} /> } - label={'Ativar/Desativar'} + label={i18n.t('configModal.titles.enableDisable')} />
{ @@ -475,13 +478,13 @@ const ConfigModal = ({ open, onClose, change }) => { checked={values.holidayDateEnable} /> } - label={'Ativar/Desativar'} + label={i18n.t('configModal.titles.enableDisable')} />
{ checked={values.ticketExpirationEnable} /> } - label={'Ativar/Desativar'} + label={i18n.t('configModal.titles.enableDisable')} />
{ size={24} className={classes.buttonProgress} /> - ) : 'Salvar'} + ) : i18n.t('configModal.titles.save')} diff --git a/frontend/src/components/DashboardUser/CardUser.jsx b/frontend/src/components/DashboardUser/CardUser.jsx index eea89d1..bd595dd 100644 --- a/frontend/src/components/DashboardUser/CardUser.jsx +++ b/frontend/src/components/DashboardUser/CardUser.jsx @@ -23,6 +23,8 @@ import CheckCircleIcon from "@material-ui/icons/CheckCircle"; import ErrorIcon from "@material-ui/icons/Error"; import RemoveCircleIcon from "@material-ui/icons/RemoveCircle"; +import { i18n } from "../../translate/i18n"; + const CardUser = ({ classes, usersOnlineInfo, logout }) => { const [search, setSearch] = React.useState(""); @@ -46,14 +48,14 @@ const CardUser = ({ classes, usersOnlineInfo, logout }) => { color="primary" style={{ marginBottom: "16px" }} > - Lista de Usuários + {i18n.t('dashboard.titles.listUser')} { Todos Online Offline - Não entrou + {i18n.t('dashboard.titles.notEnter')} @@ -161,7 +163,7 @@ const CardUser = ({ classes, usersOnlineInfo, logout }) => { {user.sumOnlineTime && user.sumOnlineTime.sum ? user.sumOnlineTime.sum - : "Não entrou Hoje"} + : i18n.t('dashboard.titles.notEnterToday')} diff --git a/frontend/src/components/ModalUpdateScheduleReminder/DatePicker2/index.js b/frontend/src/components/ModalUpdateScheduleReminder/DatePicker2/index.js index a4e953e..0dd343c 100644 --- a/frontend/src/components/ModalUpdateScheduleReminder/DatePicker2/index.js +++ b/frontend/src/components/ModalUpdateScheduleReminder/DatePicker2/index.js @@ -13,7 +13,7 @@ import { import ptBrLocale from "date-fns/locale/pt-BR"; - +import esLocale from 'date-fns/locale/es'; function formatDateDatePicker(data){ return String(new Date(data).getFullYear())+'-'+ @@ -50,7 +50,7 @@ function ResponsiveDatePickers(props) { return ( - + { - + - + { const dataChat = props.data.map((dt) => { return { - 'fromMe': dt.fromMe ? 'Atendente' : 'Cliente', + 'fromMe': dt.fromMe ? i18n.t('dashboard.titles.attendant') : 'Cliente', 'body': dt.body, 'createdAt': dt.createdAt } diff --git a/frontend/src/components/ReportModal/index.js b/frontend/src/components/ReportModal/index.js index 35c8216..5ae5095 100644 --- a/frontend/src/components/ReportModal/index.js +++ b/frontend/src/components/ReportModal/index.js @@ -11,7 +11,8 @@ import FormControl from '@mui/material/FormControl'; import InputLabel from '@mui/material/InputLabel'; import MenuItem from '@mui/material/MenuItem'; import Select from '@mui/material/Select'; - + +import { i18n } from "../../translate/i18n"; @@ -56,11 +57,11 @@ useEffect(()=>{ open={open} onClose={handleClose} > - Relatórios + {i18n.t('dashboard.titles.dialogTitle')} - Escolha uma opção de relatório abaixo + {i18n.t('dashboard.titles.dialogContentText')} { fullWidth />
-
- {user.sumOnlineTime ? user.sumOnlineTime.sum : "Não entrou"} + {user.sumOnlineTime ? user.sumOnlineTime.sum : i18n.t('dashboard.titles.notEnter')} {user.statusOnline && user.statusOnline.status === "online" ? ( diff --git a/frontend/src/components/PositionModal/index.js b/frontend/src/components/PositionModal/index.js index d1b68b7..4489f8d 100644 --- a/frontend/src/components/PositionModal/index.js +++ b/frontend/src/components/PositionModal/index.js @@ -5,9 +5,6 @@ import { Formik, Form, Field } from "formik" import { toast } from "react-toastify" import openSocket from 'socket.io-client' -import { i18n } from "../../translate/i18n"; - - import { makeStyles, Button, diff --git a/frontend/src/translate/languages/en.js b/frontend/src/translate/languages/en.js index e5bc319..9f10bd6 100644 --- a/frontend/src/translate/languages/en.js +++ b/frontend/src/translate/languages/en.js @@ -348,7 +348,9 @@ const messages = { title0_1: "Reminders/Schedulings", title1_1: "Calls by attendants", title2_1: "Whatsapp chat", - title3_1: "Users online/offline" + title3_1: "Users online/offline", + title4_1: "Attendance report by numbers", + title5_1: "Queue service report" }, listColumns: { column0_1: 'Actions', diff --git a/frontend/src/translate/languages/es.js b/frontend/src/translate/languages/es.js index 5021cb0..6611563 100644 --- a/frontend/src/translate/languages/es.js +++ b/frontend/src/translate/languages/es.js @@ -52,15 +52,15 @@ const messages = { } }, - table_users:{ - - title: 'Lista de usuarios', - column0: 'Nombre', - column1: 'En servicio/Terminado(S)', - column2: 'Abrir por cola', - column3: 'Cerrado por cola', - column4: 'Tiempo Online', - column5: 'Actions', + table_users: { + + title: 'Lista de usuarios', + column0: 'Nombre', + column1: 'En servicio/Terminado(S)', + column2: 'Abrir por cola', + column3: 'Cerrado por cola', + column4: 'Tiempo Online', + column5: 'Actions', }, titles: { selectQueues: 'Colas', @@ -71,8 +71,8 @@ const messages = { attendant: 'Agente', dialogTitle: 'Reportes', dialogContentText: 'Escoja una opción de reporte abajo.', - transfer: 'Transferir para outras filas', - title: 'Entradas de cierre', + transfer: 'Transferir para otras Colas', + title: 'Cierre de Tickets', confirmationModal: 'Está seguro de que desea eliminar este estado de cierre: ', status: 'Status de cierre', listUser: 'Lista de Usuarios', @@ -356,10 +356,10 @@ const messages = { title1_1: "Atención por agentes", title2_1: "Chat de whatsapp", title3_1: "Usuarios online/offline", - title4_1: "Relatório de atendimento por números", - title5_1: "Relatório de atendimento por filas" + title4_1: "Reporte de atención por números", + title5_1: "Reporte de atención por colas" }, - listColumns:{ + listColumns: { column0_1: 'Acción', column0_2: 'Pic', column0_3: 'Nombre', @@ -370,7 +370,7 @@ const messages = { column0_8: 'Mensaje', column1_1: 'Almacenar', - column1_2: 'Secretario', + column1_2: 'Secretario', column1_5: 'Tema', column1_6: 'Status', column1_7: 'Creado', diff --git a/frontend/src/translate/languages/pt.js b/frontend/src/translate/languages/pt.js index b3d8cd3..8c1af2b 100644 --- a/frontend/src/translate/languages/pt.js +++ b/frontend/src/translate/languages/pt.js @@ -75,8 +75,8 @@ const messages = { status: 'Status de encerramento', listUser: 'Lista de Usuarios', user: 'Usuario', - notEnter: 'No ingresó', - notEnterToday: 'Não entrou' + notEnter: 'Não entrou', + notEnterToday: 'Não entrou hoje' } }, reportOptType: { From e8227661e075ec5161a1c7bcc56100986e8c055f Mon Sep 17 00:00:00 2001 From: adriano Date: Fri, 26 Jul 2024 16:08:18 -0500 Subject: [PATCH 17/23] fix(i18n): resolve translation issues --- frontend/src/pages/Dashboard/index.js | 2 +- frontend/src/translate/languages/en.js | 3 ++- frontend/src/translate/languages/es.js | 3 ++- frontend/src/translate/languages/pt.js | 3 ++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/frontend/src/pages/Dashboard/index.js b/frontend/src/pages/Dashboard/index.js index 99bbd0a..9337cc0 100644 --- a/frontend/src/pages/Dashboard/index.js +++ b/frontend/src/pages/Dashboard/index.js @@ -520,7 +520,7 @@ const Dashboard = () => { variant="outlined" > - Fechados + {i18n.t('dashboard.titles.ticketsClosed')} diff --git a/frontend/src/translate/languages/en.js b/frontend/src/translate/languages/en.js index 9f10bd6..1b28d36 100644 --- a/frontend/src/translate/languages/en.js +++ b/frontend/src/translate/languages/en.js @@ -75,7 +75,8 @@ const messages = { listUser: 'List user', user: 'user', notEnter: 'Did not enter', - notEnterToday: 'Did not enter today' + notEnterToday: 'Did not enter today', + ticketsClosed: 'Closed' } }, reportOptType: { diff --git a/frontend/src/translate/languages/es.js b/frontend/src/translate/languages/es.js index 6611563..b6a1d29 100644 --- a/frontend/src/translate/languages/es.js +++ b/frontend/src/translate/languages/es.js @@ -78,7 +78,8 @@ const messages = { listUser: 'Lista de Usuarios', user: 'Usuario', notEnter: 'No ingresó', - notEnterToday: 'No ingresó hoy' + notEnterToday: 'No ingresó hoy', + ticketsClosed: 'Cerrados' } }, reportOptType: { diff --git a/frontend/src/translate/languages/pt.js b/frontend/src/translate/languages/pt.js index 8c1af2b..01a2a19 100644 --- a/frontend/src/translate/languages/pt.js +++ b/frontend/src/translate/languages/pt.js @@ -76,7 +76,8 @@ const messages = { listUser: 'Lista de Usuarios', user: 'Usuario', notEnter: 'Não entrou', - notEnterToday: 'Não entrou hoje' + notEnterToday: 'Não entrou hoje', + ticketsClosed: 'Fechados' } }, reportOptType: { From 3e88b27021c868118eedfc53961940bf1a46a777 Mon Sep 17 00:00:00 2001 From: adriano Date: Fri, 9 Aug 2024 16:45:25 -0300 Subject: [PATCH 18/23] feat: add 24-hour window and service category for official WhatsApp conversations in Redis; implement method to send billing info to API for Grafana usage report --- backend/src/controllers/WhatsAppController.ts | 97 ++++++++++++++++++- backend/src/helpers/RedisClient.ts | 40 ++++++++ 2 files changed, 136 insertions(+), 1 deletion(-) diff --git a/backend/src/controllers/WhatsAppController.ts b/backend/src/controllers/WhatsAppController.ts index 0158748..b442e79 100644 --- a/backend/src/controllers/WhatsAppController.ts +++ b/backend/src/controllers/WhatsAppController.ts @@ -41,7 +41,10 @@ import { getSettingValue } from "../helpers/WhaticketSettings"; import ListWhatsAppsNumber from "../services/WhatsappService/ListWhatsAppsNumber"; import SettingTicket from "../models/SettingTicket"; import { Op } from "sequelize"; -import { del, get, set } from "../helpers/RedisClient"; +import { del, get, getKeysByPattern, set, setCBPWhatsappOfficial } from "../helpers/RedisClient"; + +import axios from "axios"; + interface WhatsappData { name: string; @@ -214,6 +217,48 @@ export const weebhook = async ( return res.sendStatus(500); } + if( + req?.body?.entry?.length > 0 && + req?.body?.entry[0]?.changes?.length > 0 && + req?.body?.entry[0]?.changes?.length > 0 && + req?.body?.entry[0]?.changes[0]?.value?.statuses?.length>0 && + req?.body?.entry[0]?.changes[0]?.value?.statuses[0]?.recipient_id && + req?.body?.entry[0]?.changes[0]?.value?.statuses[0]?.conversation?.origin?.type){ + + const company_phone = req?.body?.entry[0]?.changes[0]?.value?.metadata?.display_phone_number + const client_phone = req?.body?.entry[0]?.changes[0]?.value?.statuses[0]?.recipient_id + const conversation_type = req?.body?.entry[0]?.changes[0]?.value?.statuses[0].conversation.origin.type + const billable = req?.body?.entry[0]?.changes[0]?.value?.statuses[0].pricing.billable + const pricing_model = req?.body?.entry[0]?.changes[0]?.value?.statuses[0].pricing.pricing_model + const conversation_type_category = req?.body?.entry[0]?.changes[0]?.value?.statuses[0].pricing.category + const msg_id = req?.body?.entry[0]?.changes[0]?.value?.statuses[0].id + + const _contact_to_exist = await get({ + key: "whatsapp:*", + value: `${company_phone}` + }); + + if(_contact_to_exist){ + + const lst_services_cbp = await getKeysByPattern(company_phone, client_phone, conversation_type_category) + + if(lst_services_cbp && lst_services_cbp.length > 0){ + for(const item of lst_services_cbp){ + if(!item.split(':').includes(conversation_type_category)){ + await setCBP(msg_id, company_phone, client_phone, conversation_type_category, billable, pricing_model) + } + } + }else{ + await setCBP(msg_id, company_phone, client_phone, conversation_type_category, billable, pricing_model) + + } + + console.log('_contact_to_exist: ', _contact_to_exist) + } + + + } + // MESSAGE if (req.body.object) { if ( @@ -626,3 +671,53 @@ const checkWhatsAppData = ({ return { message: "urlApi is required!" }; } }; + +async function setCBP(msg_id: any, company_phone: any, client_phone: any, conversation_type_category: any, billable:string, pricing_model:string) { + const message = await Message.findByPk(msg_id) + + if (message) { + await setCBPWhatsappOfficial(company_phone, client_phone, conversation_type_category, msg_id, `${message.ticketId}`) + + await sendToAPIUsage(msg_id, + company_phone, + client_phone, + conversation_type_category, + `${message.ticketId}`, + billable, + pricing_model + ) + } +} + + + +async function sendToAPIUsage(msg_id: any, company_phone: any, client_phone: any, conversation_type_category: any, ticketId: any, billable:string, pricing_model:string) { + const data = JSON.stringify({ + "companyId": company_phone, + "provider": "meta", + "product": "whatsapp", + "type": conversation_type_category, + "msgId": msg_id, + "ticketId": `${ticketId}`, + "billable": billable, + "pricing_model": pricing_model + }); + + const config = { + method: 'post', + url: 'http://172.31.187.24:6008/api/v1/billing/usage-whatsapp', + headers: { + 'Authorization': 'Bearer 2ivck10D3o9qAZi0pkKudVDl9bdEVXY2s8gdxZ0jYgL1DZWTgDz6wDiIjlWgYmJtVOoqf0b42ZTLBRrfo8WoAaScRsujz3jQUNXdchSg0o43YilZGmVhheGJNAeIQRknHEll4nRJ7avcFgmDGoYbEey7TSC8EHS4Z3gzeufYYSfnKNDBwwzBURIQrTOxYFe3tBHsGOzwnuD2lU5tnEx7tr2XRO4zRNYeNY4lMBOFM0mRuyAe4kuqTrKXmJ8As200', + 'Content-Type': 'application/json' + }, + data: data + }; + + try { + const response = await axios(config); + console.log('Response from whatsapp api usage: ',JSON.stringify(response.data)); + } catch (error) { + console.log('Error on try register the whatsapp usage: ', error); + } + +} \ No newline at end of file diff --git a/backend/src/helpers/RedisClient.ts b/backend/src/helpers/RedisClient.ts index 2520588..19c828d 100644 --- a/backend/src/helpers/RedisClient.ts +++ b/backend/src/helpers/RedisClient.ts @@ -158,6 +158,46 @@ export async function findObject( return result; } +export async function setCBPWhatsappOfficial( + company_phone:string, + client_phone:string, + conversation_type:string, + msg_id: string, + ticketId?: string +) { + const key = `company_phone:${company_phone}:client_phone:${client_phone}:conversation_type:${conversation_type}`; + const result = await redis.hmset( + key, + "company_phone", + company_phone, + "client_phone", + client_phone, + "conversation_type", + conversation_type, + "msg_id", + msg_id, + "ticketId", + ticketId + ); + + await redis.expire(key, 86400); +} + + +export async function getKeysByPattern(company_phone:string, client_phone:string, conversation_type:string,) { + const pattern = `company_phone:${company_phone}:client_phone:${client_phone}:conversation_type:${conversation_type}*`; + const keys = []; + let cursor = "0"; + + do { + const result = await redis.scan(cursor, "MATCH", pattern, "COUNT", 100); + cursor = result[0]; + keys.push(...result[1]); + } while (cursor !== "0"); + + return keys; +} + export async function deleteObject( whatsappId: string, contactId: string, From dc44dccd827dfc00071123e52172b7ff9ea609ee Mon Sep 17 00:00:00 2001 From: adriano Date: Tue, 13 Aug 2024 10:43:32 -0300 Subject: [PATCH 19/23] feat: Upadate pyload properties to send client phone to the whatsapp official billing api --- backend/src/controllers/WhatsAppController.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/backend/src/controllers/WhatsAppController.ts b/backend/src/controllers/WhatsAppController.ts index c6eea35..d6c2077 100644 --- a/backend/src/controllers/WhatsAppController.ts +++ b/backend/src/controllers/WhatsAppController.ts @@ -697,12 +697,15 @@ async function setCBP(msg_id: any, company_phone: any, client_phone: any, conver async function sendToAPIUsage(msg_id: any, company_phone: any, client_phone: any, conversation_type_category: any, ticketId: any, billable:string, pricing_model:string) { const data = JSON.stringify({ - "companyId": company_phone, + "companyId": process.env.COMPANY_ID || company_phone, + "companyPhone": company_phone, + "clientPhone": client_phone, "provider": "meta", "product": "whatsapp", "type": conversation_type_category, "msgId": msg_id, "ticketId": `${ticketId}`, + "ticketUrl": `${process.env.FRONTEND_URL}/tickets/${ticketId}`, "billable": billable, "pricing_model": pricing_model }); From 125e758a18d7248fea61416ceaf51dc2b52e8f6f Mon Sep 17 00:00:00 2001 From: adriano Date: Thu, 22 Aug 2024 16:51:31 -0300 Subject: [PATCH 20/23] firt commit --- backend/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/package.json b/backend/package.json index 1e5bd13..7bfa886 100644 --- a/backend/package.json +++ b/backend/package.json @@ -53,6 +53,7 @@ "yup": "^0.32.8" }, "devDependencies": { + "@types/lodash": "4.14", "@types/bcryptjs": "^2.4.2", "@types/bluebird": "^3.5.32", "@types/cookie-parser": "^1.4.2", From 0a031bd9a8a0ee493747b4dc939c7bea0273c353 Mon Sep 17 00:00:00 2001 From: adriano Date: Thu, 29 Aug 2024 18:09:00 -0300 Subject: [PATCH 21/23] fix issues for websocket merge --- backend/src/libs/socket.ts | 12 ++++++------ frontend/server.js | 2 +- frontend/src/components/TicketsManager/index.js | 12 ++++++------ frontend/src/services/api.js | 2 +- frontend/src/services/socket.js | 15 ++++++++------- 5 files changed, 22 insertions(+), 21 deletions(-) diff --git a/backend/src/libs/socket.ts b/backend/src/libs/socket.ts index 8412760..291ceaa 100644 --- a/backend/src/libs/socket.ts +++ b/backend/src/libs/socket.ts @@ -59,14 +59,14 @@ export const initIO = (httpServer: Server): SocketIO => { io = new SocketIO(httpServer, { cors: { - origin: "*", - allowedHeaders: ["my-custom-header"], - credentials: true + origin: process.env.FRONTEND_URL, + //allowedHeaders: ["my-custom-header"], + //credentials: true }, maxHttpBufferSize: 1e8, - pingInterval: 25000, - pingTimeout: 60000, - adapter: createAdapter(pubClient, subClient) + // pingInterval: 25000, + // pingTimeout: 60000, + // adapter: createAdapter(pubClient, subClient) }); diff --git a/frontend/server.js b/frontend/server.js index ff983c1..a05ba32 100644 --- a/frontend/server.js +++ b/frontend/server.js @@ -6,4 +6,4 @@ app.use(express.static(path.join(__dirname, "build"))); app.get("/*", function (req, res) { res.sendFile(path.join(__dirname, "build", "index.html")); }); -app.listen(3331); +app.listen(3333); diff --git a/frontend/src/components/TicketsManager/index.js b/frontend/src/components/TicketsManager/index.js index 18bd1c8..4699948 100644 --- a/frontend/src/components/TicketsManager/index.js +++ b/frontend/src/components/TicketsManager/index.js @@ -152,7 +152,7 @@ const TicketsManager = () => { const [openCount, setOpenCount] = useState(0) const [pendingCount, setPendingCount] = useState(0) - const userQueueIds = user.queues.map((q) => q.id) + const userQueueIds = user?.queues?.map((q) => q?.id) const [selectedQueueIds, setSelectedQueueIds] = useState(userQueueIds || []) const [showContentSearch, setShowContentSearch] = useState(false) @@ -177,9 +177,9 @@ const TicketsManager = () => { }, [setting]) useEffect(() => { - if (user.profile.toUpperCase() === "ADMIN" || - user.profile.toUpperCase() === "SUPERVISOR" || - user.profile.toUpperCase() === "MASTER") { + if (user?.profile?.toUpperCase() === "ADMIN" || + user?.profile?.toUpperCase() === "SUPERVISOR" || + user?.profile?.toUpperCase() === "MASTER") { setShowAllTickets(true) } // eslint-disable-next-line react-hooks/exhaustive-deps @@ -202,11 +202,11 @@ const TicketsManager = () => { if (tickets.length > 0) { const now = new Date() const differenceTime = tickets?.map(ticket => { - const createdAt = new Date(ticket.createdAt) + const createdAt = new Date(ticket?.createdAt) const difference = now - createdAt return difference }) - const sumDifferences = differenceTime.reduce((total, difference) => total + difference, 0) + const sumDifferences = differenceTime?.reduce((total, difference) => total + difference, 0) const averageTimeMilliseconds = sumDifferences / tickets?.length let hours = Math.floor(averageTimeMilliseconds / 3600000) const minutes = Math.floor((averageTimeMilliseconds % 3600000) / 60000) diff --git a/frontend/src/services/api.js b/frontend/src/services/api.js index 116eac5..209fc12 100644 --- a/frontend/src/services/api.js +++ b/frontend/src/services/api.js @@ -1,7 +1,7 @@ import axios from "axios"; const api = axios.create({ - baseURL: process.env.REACT_APP_BACKEND_URL + "/api", + baseURL: process.env.REACT_APP_BACKEND_URL, withCredentials: true, }); diff --git a/frontend/src/services/socket.js b/frontend/src/services/socket.js index e0b4950..b54fe15 100644 --- a/frontend/src/services/socket.js +++ b/frontend/src/services/socket.js @@ -3,11 +3,12 @@ import { io } from 'socket.io-client'; // "undefined" means the URL will be computed from the `window.location` object const URL = process.env.REACT_APP_BACKEND_URL -export const socket = io(URL, { - path: "/api-ws/socketio", - withCredentials: true, - extraHeaders: { - "my-custom-header": "abcd" - }, +export const socket = io(URL, +//{ +// withCredentials: true, +// extraHeaders: { +// "my-custom-header": "abcd" +// }, // transports: ['websocket', 'polling'] -}); \ No newline at end of file +//} +); \ No newline at end of file From 05c9f3af6d9a84da12dca7c9af8175b6256c701c Mon Sep 17 00:00:00 2001 From: gustavo-gsp Date: Thu, 5 Sep 2024 12:20:52 -0300 Subject: [PATCH 22/23] perf: improve backend with compression and optimize frontend with lazy load Details: - Added compression to the backend to reduce page load times. - Implemented lazy loading in frontend routes to optimize page loading performance. --- backend/package.json | 4 +- backend/src/app.ts | 2 + frontend/src/routes/Route.js | 15 +++- frontend/src/routes/index.js | 145 ++++++++++++++++------------------- package-lock.json | 2 +- 5 files changed, 85 insertions(+), 83 deletions(-) diff --git a/backend/package.json b/backend/package.json index b9dd70b..bacb9d8 100644 --- a/backend/package.json +++ b/backend/package.json @@ -22,6 +22,7 @@ "@types/pino": "^6.3.4", "axios": "^1.2.3", "bcryptjs": "^2.4.3", + "compression": "^1.7.4", "cookie-parser": "^1.4.5", "cors": "^2.8.5", "date-fns": "^2.30.0", @@ -55,9 +56,9 @@ "yup": "^0.32.8" }, "devDependencies": { - "@types/lodash": "4.14", "@types/bcryptjs": "^2.4.2", "@types/bluebird": "^3.5.32", + "@types/compression": "^1.7.5", "@types/cookie-parser": "^1.4.2", "@types/cors": "^2.8.7", "@types/express": "^4.17.13", @@ -65,6 +66,7 @@ "@types/faker": "^5.1.3", "@types/jest": "^26.0.15", "@types/jsonwebtoken": "^8.5.0", + "@types/lodash": "4.14", "@types/multer": "^1.4.4", "@types/node": "^14.11.8", "@types/supertest": "^2.0.10", diff --git a/backend/src/app.ts b/backend/src/app.ts index fea4c81..7fe1d45 100644 --- a/backend/src/app.ts +++ b/backend/src/app.ts @@ -11,6 +11,7 @@ import uploadConfig from "./config/upload"; import AppError from "./errors/AppError"; import routes from "./routes"; import { logger } from "./utils/logger"; +import compression from 'compression'; Sentry.init({ dsn: process.env.SENTRY_DSN }); @@ -23,6 +24,7 @@ app.use( }) ); +app.use(compression()); app.use(cookieParser()); app.use(express.json()); app.use(Sentry.Handlers.requestHandler()); diff --git a/frontend/src/routes/Route.js b/frontend/src/routes/Route.js index fab61b3..91ce315 100644 --- a/frontend/src/routes/Route.js +++ b/frontend/src/routes/Route.js @@ -1,9 +1,14 @@ -import React, { useContext } from "react"; +import React, { useContext, Suspense, lazy } from "react"; import { Route as RouterRoute, Redirect } from "react-router-dom"; import { AuthContext } from "../context/Auth/AuthContext"; import BackdropLoading from "../components/BackdropLoading"; +// Exemplo de como você carregaria componentes de forma lazy +const Dashboard = lazy(() => import("../pages/Dashboard")); +const Login = lazy(() => import("../pages/Login")); +const Signup = lazy(() => import("../pages/Signup")); + const Route = ({ component: Component, isPrivate = false, ...rest }) => { const { isAuth, loading } = useContext(AuthContext); @@ -20,7 +25,7 @@ const Route = ({ component: Component, isPrivate = false, ...rest }) => { return ( <> {loading && } - ; + ); } @@ -28,9 +33,11 @@ const Route = ({ component: Component, isPrivate = false, ...rest }) => { return ( <> {loading && } - + }> + + ); }; -export default Route; +export default Route; \ No newline at end of file diff --git a/frontend/src/routes/index.js b/frontend/src/routes/index.js index 3400c44..8f053a4 100644 --- a/frontend/src/routes/index.js +++ b/frontend/src/routes/index.js @@ -1,94 +1,85 @@ -import React from 'react' +import React, { Suspense, lazy } from 'react'; import { BrowserRouter, Switch } from 'react-router-dom' import { ToastContainer } from 'react-toastify' -import LoggedInLayout from '../layout' -import Dashboard from '../pages/Dashboard/' - -import Report from '../pages/Report/' -import SchedulesReminder from '../pages/SchedulesReminder/' - -import Tickets from '../pages/Tickets/' -import Signup from '../pages/Signup/' -import Login from '../pages/Login/' -import Connections from '../pages/Connections/' -import Campaign from '../pages/Campaign' -import Settings from '../pages/Settings/' -import Users from '../pages/Users' -import Contacts from '../pages/Contacts/' -import QuickAnswers from '../pages/QuickAnswers/' -import StatusChatEnd from '../pages/StatusChatEnd/' -import Position from '../pages/Position/' - -import Queues from '../pages/Queues/' import { AuthProvider } from '../context/Auth/AuthContext' import { WhatsAppsProvider } from '../context/WhatsApp/WhatsAppsContext' +import LoggedInLayout from '../layout' import Route from './Route' +import BackdropLoading from "../components/BackdropLoading"; + +const Dashboard = lazy(() => import('../pages/Dashboard/')); +const Report = lazy(() => import('../pages/Report/')); +const SchedulesReminder = lazy(() => import('../pages/SchedulesReminder/')); +const Tickets = lazy(() => import('../pages/Tickets/')); +const Signup = lazy(() => import('../pages/Signup/')); +const Login = lazy(() => import('../pages/Login/')); +const Connections = lazy(() => import('../pages/Connections/')); +const Campaign = lazy(() => import('../pages/Campaign/')); +const Settings = lazy(() => import('../pages/Settings/')); +const Users = lazy(() => import('../pages/Users/')); +const Contacts = lazy(() => import('../pages/Contacts/')); +const QuickAnswers = lazy(() => import('../pages/QuickAnswers/')); +const StatusChatEnd = lazy(() => import('../pages/StatusChatEnd/')); +const Position = lazy(() => import('../pages/Position/')); +const Queues = lazy(() => import('../pages/Queues/')); const Routes = () => { return ( - - - - - - - - - - - - - - - - - - - - - - - - - - + }> + + + + + + + + + + + + + + + + + + + + + + - ) + ); } export default Routes diff --git a/package-lock.json b/package-lock.json index f1ff13b..e17b739 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "whaticket", + "name": "projeto-hit", "lockfileVersion": 2, "requires": true, "packages": { From f4f5dad8d290f266ad1cfa30ee1dc5da707445dd Mon Sep 17 00:00:00 2001 From: gustavo-gsp Date: Fri, 6 Sep 2024 16:59:23 -0300 Subject: [PATCH 23/23] fix: resolve issue of creating multiple contacts for the same WhatsApp number of a client Details: - Fixed the bug that allowed the creation of more than one contact for the same WhatsApp number of a client. --- .../CreateOrUpdateContactService.ts | 35 +++++++++++++++---- .../FindOrCreateTicketServiceBot.ts | 4 --- .../WbotServices/wbotMessageListener.ts | 2 -- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/backend/src/services/ContactServices/CreateOrUpdateContactService.ts b/backend/src/services/ContactServices/CreateOrUpdateContactService.ts index 50d5d5f..e63085d 100644 --- a/backend/src/services/ContactServices/CreateOrUpdateContactService.ts +++ b/backend/src/services/ContactServices/CreateOrUpdateContactService.ts @@ -1,5 +1,6 @@ import { getIO } from "../../libs/socket"; import Contact from "../../models/Contact"; +const { Op } = require('sequelize'); import { createOrUpdateContactCache } from '../../helpers/ContactsCache' import { tr } from "date-fns/locale"; @@ -35,15 +36,37 @@ const CreateOrUpdateContactService = async ({ const io = getIO(); let contact: Contact | null; - - contact = await Contact.findOne({ where: { number } }); + const firstFourDigits = number.slice(0, 4); + const lastEightDigits = number.slice(-8); + + //const numberFormat = number?.length === 13 && number[4] == '9' ? number.slice(0, 4) + number.slice(0, 4) : number; + //contact = await Contact.findOne({ where: { number } }); + contact = await Contact.findOne({ + where: { + [Op.and]: [ + { + number: { + [Op.like]: `%${firstFourDigits}%` + } + }, + { + number: { + [Op.like]: `%${lastEightDigits}%` + } + } + ] + } + }); if (contact) { - contact.update({ profilePicUrl }); - // TEST DEL - await createOrUpdateContactCache(`contact:${contact.id}`, { profilePicUrl }) - // + if(contact.number == number){ + contact.update({ profilePicUrl }); + await createOrUpdateContactCache(`contact:${contact.id}`, { profilePicUrl }) + } else{ + contact.update({ profilePicUrl, number }); + await createOrUpdateContactCache(`contact:${contact.id}`, { profilePicUrl, number }) + } io.emit("contact", { action: "update", diff --git a/backend/src/services/TicketServices/FindOrCreateTicketServiceBot.ts b/backend/src/services/TicketServices/FindOrCreateTicketServiceBot.ts index 42d7d53..8599030 100644 --- a/backend/src/services/TicketServices/FindOrCreateTicketServiceBot.ts +++ b/backend/src/services/TicketServices/FindOrCreateTicketServiceBot.ts @@ -101,8 +101,6 @@ const FindOrCreateTicketServiceBot = async ( unreadMessages }); - console.log("lxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); - await dialogFlowStartContext(contact, ticket, botInfo); } } @@ -128,8 +126,6 @@ const FindOrCreateTicketServiceBot = async ( phoneNumberId }); - console.log("yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"); - await dialogFlowStartContext(contact, ticket, botInfo); } diff --git a/backend/src/services/WbotServices/wbotMessageListener.ts b/backend/src/services/WbotServices/wbotMessageListener.ts index 53b50e2..27a5131 100644 --- a/backend/src/services/WbotServices/wbotMessageListener.ts +++ b/backend/src/services/WbotServices/wbotMessageListener.ts @@ -748,8 +748,6 @@ const handleMessage = async ( // console.log('----------> chat: ', JSON.parse(JSON.stringify(chat))) - console - if (chat.isGroup) { // let msgGroupContact;