From 31bce333da1477429b647d8a066069c2afb53572 Mon Sep 17 00:00:00 2001 From: Danilo Alves Date: Thu, 13 Jan 2022 14:47:01 -0300 Subject: [PATCH 1/5] =?UTF-8?q?Corrigido=20problema=20na=20contagem=20de?= =?UTF-8?q?=20chamados=20e=20adicionado=20possibilidade=20de=20fechar=20ch?= =?UTF-8?q?amados=20automaticamente=20ap=C3=B3s=20um=20periodo=20de=20temp?= =?UTF-8?q?o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/.env.example | 3 +- frontend/src/hooks/useTickets/index.js | 124 +++++++++++++++---------- frontend/src/pages/Dashboard/index.js | 6 +- 3 files changed, 81 insertions(+), 52 deletions(-) diff --git a/frontend/.env.example b/frontend/.env.example index f890a22..5b7345f 100644 --- a/frontend/.env.example +++ b/frontend/.env.example @@ -1 +1,2 @@ -REACT_APP_BACKEND_URL = http://localhost:8080/ \ No newline at end of file +REACT_APP_BACKEND_URL = http://localhost:8080/ +REACT_APP_HORAS_FECHAR_CHAMADOS_AUTO = \ No newline at end of file diff --git a/frontend/src/hooks/useTickets/index.js b/frontend/src/hooks/useTickets/index.js index 97b6e7f..28a2a65 100644 --- a/frontend/src/hooks/useTickets/index.js +++ b/frontend/src/hooks/useTickets/index.js @@ -4,56 +4,84 @@ import toastError from "../../errors/toastError"; import api from "../../services/api"; const useTickets = ({ - searchParam, - pageNumber, - status, - date, - showAll, - queueIds, - withUnreadMessages, + searchParam, + pageNumber, + status, + date, + showAll, + queueIds, + withUnreadMessages, }) => { - const [loading, setLoading] = useState(true); - const [hasMore, setHasMore] = useState(false); - const [tickets, setTickets] = useState([]); + const [loading, setLoading] = useState(true); + const [hasMore, setHasMore] = useState(false); + const [tickets, setTickets] = useState([]); + const [count, setCount] = useState(0); - useEffect(() => { - setLoading(true); - const delayDebounceFn = setTimeout(() => { - const fetchTickets = async () => { - try { - const { data } = await api.get("/tickets", { - params: { - searchParam, - pageNumber, - status, - date, - showAll, - queueIds, - withUnreadMessages, - }, - }); - setTickets(data.tickets); - setHasMore(data.hasMore); - setLoading(false); - } catch (err) { - setLoading(false); - toastError(err); - } - }; - fetchTickets(); - }, 500); - return () => clearTimeout(delayDebounceFn); - }, [ - searchParam, - pageNumber, - status, - date, - showAll, - queueIds, - withUnreadMessages, - ]); + useEffect(() => { + setLoading(true); + const delayDebounceFn = setTimeout(() => { + const fetchTickets = async() => { + try { + const { data } = await api.get("/tickets", { + params: { + searchParam, + pageNumber, + status, + date, + showAll, + queueIds, + withUnreadMessages, + }, + }) + setTickets(data.tickets) - return { tickets, loading, hasMore }; + let horasFecharAutomaticamente = process.env.REACT_APP_HOURS_CLOSE_TICKETS_AUTO + + if (status === "open" && horasFecharAutomaticamente && horasFecharAutomaticamente !== "" && + horasFecharAutomaticamente !== "0" && Number(horasFecharAutomaticamente) > 0) { + + let dataLimite = new Date() + dataLimite.setHours(dataLimite.getHours() - Number(horasFecharAutomaticamente)) + + data.tickets.forEach(ticket => { + if (ticket.status !== "closed") { + let dataUltimaInteracaoChamado = new Date(ticket.updatedAt) + if (dataUltimaInteracaoChamado < dataLimite) + closeTicket(ticket) + } + }) + } + + setHasMore(data.hasMore) + setCount(data.count) + setLoading(false) + } catch (err) { + setLoading(false) + toastError(err) + } + } + + const closeTicket = async(ticket) => { + await api.put(`/tickets/${ticket.id}`, { + status: "closed", + userId: ticket.userId || null, + }) + } + + fetchTickets() + }, 500) + return () => clearTimeout(delayDebounceFn) + }, [ + searchParam, + pageNumber, + status, + date, + showAll, + queueIds, + withUnreadMessages, + ]) + + return { tickets, loading, hasMore, count }; }; -export default useTickets; +export default useTickets; \ No newline at end of file diff --git a/frontend/src/pages/Dashboard/index.js b/frontend/src/pages/Dashboard/index.js index 7d11703..eb11d19 100644 --- a/frontend/src/pages/Dashboard/index.js +++ b/frontend/src/pages/Dashboard/index.js @@ -54,13 +54,13 @@ const Dashboard = () => { const GetTickets = (status, showAll, withUnreadMessages) => { - const { tickets } = useTickets({ + const { count } = useTickets({ status: status, showAll: showAll, withUnreadMessages: withUnreadMessages, queueIds: JSON.stringify(userQueueIds) }); - return tickets.length; + return count; } return ( @@ -114,4 +114,4 @@ const Dashboard = () => { ) } -export default Dashboard +export default Dashboard \ No newline at end of file From 2c0621278b4037cf2d54b31faa13cd3f84859a05 Mon Sep 17 00:00:00 2001 From: Danilo Alves Date: Thu, 13 Jan 2022 15:35:46 -0300 Subject: [PATCH 2/5] Atualizado .env.example --- frontend/.env.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/.env.example b/frontend/.env.example index 5b7345f..b8d2f1d 100644 --- a/frontend/.env.example +++ b/frontend/.env.example @@ -1,2 +1,2 @@ REACT_APP_BACKEND_URL = http://localhost:8080/ -REACT_APP_HORAS_FECHAR_CHAMADOS_AUTO = \ No newline at end of file +REACT_APP_HOURS_CLOSE_TICKETS_AUTO = \ No newline at end of file From f1b7be45afb545f942442cd3af003d2eeefce975 Mon Sep 17 00:00:00 2001 From: Danilo Alves Date: Thu, 13 Jan 2022 16:24:36 -0300 Subject: [PATCH 3/5] =?UTF-8?q?Corrigido=20erro=20CONTACT=5FNOT=5FFIND=20a?= =?UTF-8?q?o=20renderizar=20um=20VCard=20que=20j=C3=A1=20existia=20antes?= =?UTF-8?q?=20da=20atualiza=C3=A7=C3=A3o=20nova=20dos=20VCards?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Agora caso encontre um VCard de um contato que não exista ele já faz a inclusão deste contato e o renderiza corretamente --- .../services/ContactServices/GetContactService.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/backend/src/services/ContactServices/GetContactService.ts b/backend/src/services/ContactServices/GetContactService.ts index 93b12e3..3865bc5 100644 --- a/backend/src/services/ContactServices/GetContactService.ts +++ b/backend/src/services/ContactServices/GetContactService.ts @@ -1,5 +1,6 @@ import AppError from "../../errors/AppError"; import Contact from "../../models/Contact"; +import CreateContactService from "./CreateContactService"; interface ExtraInfo { name: string; @@ -20,10 +21,18 @@ const GetContactService = async ({ name, number }: Request): Promise => }); if (!numberExists) { - throw new AppError("CONTACT_NOT_FIND"); + const contact = await CreateContactService({ + name, + number, + }) + + if (contact == null) + throw new AppError("CONTACT_NOT_FIND") + else + return contact } - return numberExists; + return numberExists }; export default GetContactService; \ No newline at end of file From 54c9a4206d41cc1a66d16d5c6e753c15595f1624 Mon Sep 17 00:00:00 2001 From: Danilo Alves Date: Fri, 14 Jan 2022 17:26:27 -0300 Subject: [PATCH 4/5] Renderizando Live Localization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Agora é possivel renderizar as localizações que outros contatos enviam --- .../WbotServices/wbotMessageListener.ts | 25 +++++++-- .../src/components/LocationPreview/index.js | 52 +++++++++++++++++++ .../src/components/MarkdownWrapper/index.js | 5 +- frontend/src/components/MessagesList/index.js | 19 +++++-- 4 files changed, 94 insertions(+), 7 deletions(-) create mode 100644 frontend/src/components/LocationPreview/index.js diff --git a/backend/src/services/WbotServices/wbotMessageListener.ts b/backend/src/services/WbotServices/wbotMessageListener.ts index ea5eb0d..598f723 100644 --- a/backend/src/services/WbotServices/wbotMessageListener.ts +++ b/backend/src/services/WbotServices/wbotMessageListener.ts @@ -114,6 +114,10 @@ const verifyMessage = async ( ticket: Ticket, contact: Contact ) => { + + if (msg.type === 'location') + msg = prepareLocation(msg); + const quotedMsg = await verifyQuotedMessage(msg); const messageData = { id: msg.id.id, @@ -126,11 +130,25 @@ const verifyMessage = async ( quotedMsgId: quotedMsg?.id }; - await ticket.update({ lastMessage: msg.body }); + await ticket.update({ lastMessage: msg.type === "location" ? msg.description ? "Localization - " + msg.description.split('\\n')[0] : "Localization" : msg.body }); await CreateMessageService({ messageData }); }; +const prepareLocation = (msg: WbotMessage): WbotMessage => { + console.log(msg) + let gmapsUrl = "https://maps.google.com/maps?q=" + msg.location.latitude + "%2C" + msg.location.longitude + "&z=17&hl=pt-BR"; + + msg.body = "data:image/png;base64," + msg.body + "|" + gmapsUrl; + + msg.body += "|" + (msg.description != undefined ? msg.description : (msg.location.latitude + ", " + msg.location.longitude)) + + console.log(msg.body) + console.log(msg.description) + + return msg; +}; + const verifyQueue = async ( wbot: Session, msg: WbotMessage, @@ -199,7 +217,8 @@ const isValidMsg = (msg: WbotMessage): boolean => { msg.type === "document" || msg.type === "vcard" || //msg.type === "multi_vcard" || - msg.type === "sticker" + msg.type === "sticker" || + msg.type === "location" ) return true; return false; @@ -225,7 +244,7 @@ const handleMessage = async ( // media messages sent from me from cell phone, first comes with "hasMedia = false" and type = "image/ptt/etc" // in this case, return and let this message be handled by "media_uploaded" event, when it will have "hasMedia = true" - if (!msg.hasMedia && msg.type !== "chat" && msg.type !== "vcard" + if (!msg.hasMedia && msg.type !== "location" && msg.type !== "chat" && msg.type !== "vcard" //&& msg.type !== "multi_vcard" ) return; diff --git a/frontend/src/components/LocationPreview/index.js b/frontend/src/components/LocationPreview/index.js new file mode 100644 index 0000000..a2dd210 --- /dev/null +++ b/frontend/src/components/LocationPreview/index.js @@ -0,0 +1,52 @@ +import React, { useEffect } from 'react'; +import toastError from "../../errors/toastError"; + +import Typography from "@material-ui/core/Typography"; +import Grid from "@material-ui/core/Grid"; + +import { Button, Divider, } from "@material-ui/core"; + +const LocationPreview = ({ image, link, description }) => { + useEffect(() => {}, [image, link, description]); + + const handleLocation = async() => { + try { + window.open(link); + } catch (err) { + toastError(err); + } + } + + return ( + <> +
+ + + + + { description && ( + + +
') }}>
+
+
+ )} + + + + +
+
+ + ); + +}; + +export default LocationPreview; \ No newline at end of file diff --git a/frontend/src/components/MarkdownWrapper/index.js b/frontend/src/components/MarkdownWrapper/index.js index 29ea445..5a65ee1 100644 --- a/frontend/src/components/MarkdownWrapper/index.js +++ b/frontend/src/components/MarkdownWrapper/index.js @@ -153,10 +153,13 @@ const MarkdownWrapper = ({ children }) => { const boldRegex = /\*(.*?)\*/g; const tildaRegex = /~(.*?)~/g; - if(children.includes('BEGIN:VCARD')) + if(children && children.includes('BEGIN:VCARD')) //children = "Diga olá ao seu novo contato clicando em *conversar*!"; children = null; + if(children && children.includes('data:image/')) + children = null; + if (children && boldRegex.test(children)) { children = children.replace(boldRegex, "**$1**"); } diff --git a/frontend/src/components/MessagesList/index.js b/frontend/src/components/MessagesList/index.js index 5a9cf21..8e2a336 100644 --- a/frontend/src/components/MessagesList/index.js +++ b/frontend/src/components/MessagesList/index.js @@ -23,6 +23,7 @@ import { import MarkdownWrapper from "../MarkdownWrapper"; import VcardPreview from "../VcardPreview"; +import LocationPreview from "../LocationPreview"; import ModalImageCors from "../ModalImageCors"; import MessageOptionsMenu from "../MessageOptionsMenu"; import whatsBackground from "../../assets/wa-background.png"; @@ -414,7 +415,19 @@ const MessagesList = ({ ticketId, isGroup }) => { }; const checkMessageMedia = (message) => { - if (message.mediaType === "vcard") { + if(message.mediaType === "location" && message.body.split('|').length >= 2) { + let locationParts = message.body.split('|') + let imageLocation = locationParts[0] + let linkLocation = locationParts[1] + + let descriptionLocation = null + + if(locationParts.length > 2) + descriptionLocation = message.body.split('|')[2] + + return + } + else if (message.mediaType === "vcard") { //console.log("vcard") //console.log(message) let array = message.body.split("\n"); @@ -604,7 +617,7 @@ const MessagesList = ({ ticketId, isGroup }) => { {message.contact?.name} )} - {(message.mediaUrl || message.mediaType === "vcard" + {(message.mediaUrl || message.mediaType === "location" || message.mediaType === "vcard" //|| message.mediaType === "multi_vcard" ) && checkMessageMedia(message)}
@@ -633,7 +646,7 @@ const MessagesList = ({ ticketId, isGroup }) => { > - {(message.mediaUrl || message.mediaType === "vcard" + {(message.mediaUrl || message.mediaType === "location" || message.mediaType === "vcard" //|| message.mediaType === "multi_vcard" ) && checkMessageMedia(message)}
Date: Mon, 17 Jan 2022 10:27:25 -0300 Subject: [PATCH 5/5] =?UTF-8?q?Melhorado=20o=20visual=20e=20feedback=20dos?= =?UTF-8?q?=20cards=20de=20localiza=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WbotServices/wbotMessageListener.ts | 10 +++------ .../src/components/LocationPreview/index.js | 21 ++++++++++--------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/backend/src/services/WbotServices/wbotMessageListener.ts b/backend/src/services/WbotServices/wbotMessageListener.ts index 598f723..2ed155b 100644 --- a/backend/src/services/WbotServices/wbotMessageListener.ts +++ b/backend/src/services/WbotServices/wbotMessageListener.ts @@ -3,7 +3,7 @@ import { promisify } from "util"; import { writeFile } from "fs"; import * as Sentry from "@sentry/node"; -import { +import WAWebJS, { Contact as WbotContact, Message as WbotMessage, MessageAck, @@ -130,21 +130,17 @@ const verifyMessage = async ( quotedMsgId: quotedMsg?.id }; - await ticket.update({ lastMessage: msg.type === "location" ? msg.description ? "Localization - " + msg.description.split('\\n')[0] : "Localization" : msg.body }); + await ticket.update({ lastMessage: msg.type === "location" ? msg.location.description ? "Localization - " + msg.location.description.split('\\n')[0] : "Localization" : msg.body }); await CreateMessageService({ messageData }); }; const prepareLocation = (msg: WbotMessage): WbotMessage => { - console.log(msg) let gmapsUrl = "https://maps.google.com/maps?q=" + msg.location.latitude + "%2C" + msg.location.longitude + "&z=17&hl=pt-BR"; msg.body = "data:image/png;base64," + msg.body + "|" + gmapsUrl; - msg.body += "|" + (msg.description != undefined ? msg.description : (msg.location.latitude + ", " + msg.location.longitude)) - - console.log(msg.body) - console.log(msg.description) + msg.body += "|" + (msg.location.description ? msg.location.description : (msg.location.latitude + ", " + msg.location.longitude)) return msg; }; diff --git a/frontend/src/components/LocationPreview/index.js b/frontend/src/components/LocationPreview/index.js index a2dd210..9187faf 100644 --- a/frontend/src/components/LocationPreview/index.js +++ b/frontend/src/components/LocationPreview/index.js @@ -22,18 +22,19 @@ const LocationPreview = ({ image, link, description }) => {
- - - - +
+
+ +
{ description && ( - - +
+
') }}>
- +
)} - +
+
- - +
+
);