Compare commits

...

5 Commits

8 changed files with 370 additions and 273 deletions

View File

@ -22,7 +22,7 @@ import format from "date-fns/format";
import ListTicketsServiceCache from "../services/TicketServices/ListTicketServiceCache"; import ListTicketsServiceCache from "../services/TicketServices/ListTicketServiceCache";
import { searchTicketCache, loadTicketsCache } from "../helpers/TicketCache"; import { searchTicketCache, loadTicketsCache } from "../helpers/TicketCache";
import { Op } from "sequelize"; import { Op, where } from "sequelize";
type IndexQuery = { type IndexQuery = {
searchParam: string; searchParam: string;
@ -119,10 +119,18 @@ export const remoteTicketCreation = async (
req: Request, req: Request,
res: Response res: Response
): Promise<Response> => { ): Promise<Response> => {
const { queueId, contact_to, msg, contact_name }: any = req.body; let { queueId, contact_from, contact_to, msg, contact_name }: any = req.body;
const validate = ["queueId", "contact_to", "msg"]; let whatsappId: any;
const validateOnlyNumber = ["queueId", "contact_to"];
if (!queueId && !contact_from) {
return res
.status(400)
.json({ error: `Property 'queueId' or 'contact_from' is required.` });
}
const validate = ["contact_to", "msg"];
const validateOnlyNumber = ["queueId", "contact_to", "contact_from"];
for (let prop of validate) { for (let prop of validate) {
if (!req.body[prop]) if (!req.body[prop])
@ -139,6 +147,7 @@ export const remoteTicketCreation = async (
} }
} }
if (queueId) {
const whatsapps = await ListWhatsAppsForQueueService(queueId, "CONNECTED"); const whatsapps = await ListWhatsAppsForQueueService(queueId, "CONNECTED");
if (!whatsapps || whatsapps?.length == 0) { if (!whatsapps || whatsapps?.length == 0) {
@ -147,7 +156,33 @@ export const remoteTicketCreation = async (
}); });
} }
const { id: whatsappId } = whatsapps[0]; const { id } = whatsapps[0];
whatsappId = id;
} else if (contact_from) {
const whatsapp = await Whatsapp.findOne({
where: { number: contact_from, status: "CONNECTED" }
});
if (!whatsapp) {
return res.status(404).json({
msg: `Whatsapp number ${contact_from} not found or disconnected!`
});
}
const { id } = whatsapp;
const { queues } = await ShowWhatsAppService(id);
if (!queues || queues.length == 0) {
return res.status(500).json({
msg: `The WhatsApp number ${contact_from} is not associated with any queue! `
});
}
queueId = queues[0].id;
whatsappId = id;
}
// const validNumber = await CheckIsValidContact(contact_to, true); // const validNumber = await CheckIsValidContact(contact_to, true);
const validNumber = contact_to; const validNumber = contact_to;

View File

@ -46,7 +46,7 @@ import FindOrCreateTicketService from "../TicketServices/FindOrCreateTicketServi
import ShowWhatsAppService from "../WhatsappService/ShowWhatsAppService"; import ShowWhatsAppService from "../WhatsappService/ShowWhatsAppService";
import { debounce } from "../../helpers/Debounce"; import { debounce } from "../../helpers/Debounce";
import UpdateTicketService from "../TicketServices/UpdateTicketService"; import UpdateTicketService from "../TicketServices/UpdateTicketService";
import { date } from "faker"; import { date, name } from "faker";
import ShowQueueService from "../QueueService/ShowQueueService"; import ShowQueueService from "../QueueService/ShowQueueService";
import ShowTicketMessage from "../TicketServices/ShowTicketMessage"; import ShowTicketMessage from "../TicketServices/ShowTicketMessage";
@ -101,6 +101,7 @@ import ShowTicketService from "../TicketServices/ShowTicketService";
import ShowQueuesByUser from "../UserServices/ShowQueuesByUser"; import ShowQueuesByUser from "../UserServices/ShowQueuesByUser";
import ListWhatsappQueuesByUserQueue from "../UserServices/ListWhatsappQueuesByUserQueue"; import ListWhatsappQueuesByUserQueue from "../UserServices/ListWhatsappQueuesByUserQueue";
import CreateContactService from "../ContactServices/CreateContactService"; import CreateContactService from "../ContactServices/CreateContactService";
import { number } from "yup";
var lst: any[] = getWhatsappIds(); var lst: any[] = getWhatsappIds();
@ -316,6 +317,14 @@ const verifyMessage = async (
await ticket.update({ lastMessage: msg.body }); await ticket.update({ lastMessage: msg.body });
if (!msg?.fromMe && msg?.vCards && msg?.vCards?.length > 0) {
if (msg.vCards.length == 1) {
messageData = { ...messageData, body: msg.vCards[0] };
} else {
messageData = { ...messageData, body: JSON.stringify(msg.vCards) };
}
}
await CreateMessageService({ messageData }); await CreateMessageService({ messageData });
}; };
@ -504,7 +513,7 @@ const isValidMsg = (msg: any): boolean => {
msg.type === "image" || msg.type === "image" ||
msg.type === "document" || msg.type === "document" ||
msg.type === "vcard" || msg.type === "vcard" ||
// msg.type === "multi_vcard" || msg.type === "multi_vcard" ||
msg.type === "sticker" msg.type === "sticker"
) )
return true; return true;
@ -550,7 +559,7 @@ const transferTicket = async (
} }
if (queue) await botTransferTicket(queue, ticket, sendGreetingMessage); if (queue) await botTransferTicket(queue, ticket, sendGreetingMessage);
io.emit('notifyPeding', {data: {ticket, queue}}); io.emit("notifyPeding", { data: { ticket, queue } });
}; };
const botTransferTicket = async ( const botTransferTicket = async (
@ -787,32 +796,8 @@ const handleMessage = async (
await verifyQueue(wbot, msg, ticket, contact); await verifyQueue(wbot, msg, ticket, contact);
} }
if (msg.type === "vcard") { if (msg.type === "vcard" || msg.type === "multi_vcard") {
try { await vcard(msg);
const array = msg.body.split("\n");
const obj = [];
let contact = "";
for (let index = 0; index < array.length; index++) {
const v = array[index];
const values = v.split(":");
for (let ind = 0; ind < values.length; ind++) {
if (values[ind].indexOf("+") !== -1) {
obj.push({ number: values[ind] });
}
if (values[ind].indexOf("FN") !== -1) {
contact = values[ind + 1];
}
}
}
for await (const ob of obj) {
const cont = await CreateContactService({
name: contact,
number: ob.number.replace(/\D/g, "")
});
}
} catch (error) {
console.log(error);
}
} }
const botInfo = await BotIsOnQueue("botqueue"); const botInfo = await BotIsOnQueue("botqueue");
@ -1258,6 +1243,59 @@ export {
mediaTypeWhatsappOfficial, mediaTypeWhatsappOfficial,
botSendMessage botSendMessage
}; };
async function vcard(msg: any) {
let array: any[] = [];
let contact: any;
let obj: any[] = [];
try {
const multi_vcard = msg?.vCards?.length === 0 ? false : true;
if (multi_vcard) {
array = msg?.vCards;
contact = [];
} else {
array = msg.body.split("\n");
contact = "";
}
for (let index = 0; index < array.length; index++) {
const v = array[index];
const values = v.split(":");
for (let ind = 0; ind < values.length; ind++) {
if (values[ind].indexOf("+") !== -1) {
obj.push({ number: values[ind] });
}
if (values[ind].indexOf("FN") !== -1) {
if (multi_vcard)
contact.push({ name: values[ind + 1].split("\n")[0] });
else contact = values[ind + 1];
}
}
}
for (const i in obj) {
let data: any = {};
if (multi_vcard) {
data = {
name: contact[i].name,
number: obj[i].number.replace(/\D/g, "")
};
} else {
data = {
name: contact,
number: obj[i].number.replace(/\D/g, "")
};
}
const cont = await CreateContactService(data);
}
} catch (error) {
console.log(error);
}
}
async function backUra(whatsappId: any, contactId: any, data: any) { async function backUra(whatsappId: any, contactId: any, data: any) {
let uraOptionSelected = await findObject(whatsappId, contactId, "ura"); let uraOptionSelected = await findObject(whatsappId, contactId, "ura");

View File

@ -157,7 +157,7 @@ const ContactCreateTicketModal = ({ modalOpen, onClose, contactId }) => {
const { data } = await api.get("/whatsapp/official/matchQueue", { params: { userId: user.id, queueId: selectedQueue }, }) const { data } = await api.get("/whatsapp/official/matchQueue", { params: { userId: user.id, queueId: selectedQueue }, })
console.log('WHATSAPP DATA: ', data) // console.log('WHATSAPP DATA: ', data)
setWhatsQueue(data) setWhatsQueue(data)

View File

@ -312,8 +312,6 @@ const MessageInput = ({ ticketStatus }) => {
const handleSendMessage = async (templateParams = null) => { const handleSendMessage = async (templateParams = null) => {
console.log('templateParams: ', templateParams, ' | inputMessage: ', inputMessage)
if (inputMessage.trim() === "") return if (inputMessage.trim() === "") return
setLoading(true) setLoading(true)
@ -324,8 +322,6 @@ const MessageInput = ({ ticketStatus }) => {
if (templateParams) { if (templateParams) {
for (let key in templateParams) { for (let key in templateParams) {
if (templateParams.hasOwnProperty(key)) { if (templateParams.hasOwnProperty(key)) {
// let value = templateParams[key]
// console.log('key: ', key, ' | ', 'VALUE: ', value)
if (key === '_reactName') { if (key === '_reactName') {
templateParams = null templateParams = null
@ -350,8 +346,6 @@ const MessageInput = ({ ticketStatus }) => {
try { try {
console.log('kkkkkkkkkkkkkkkkkkk message: ', message)
const { data } = await api.post(`/messages/${ticketId}`, message) const { data } = await api.post(`/messages/${ticketId}`, message)
setParams(null) setParams(null)
if (data && data?.data && Array.isArray(data.data)) { if (data && data?.data && Array.isArray(data.data)) {

View File

@ -1,18 +1,18 @@
import React, { useContext, useState, useEffect, useReducer, useRef } from "react"; import React, { useContext, useState, useEffect, useReducer, useRef } from "react"
import { isSameDay, parseISO, format } from "date-fns"; import { isSameDay, parseISO, format } from "date-fns"
import openSocket from "socket.io-client"; import openSocket from "socket.io-client"
import clsx from "clsx"; import clsx from "clsx"
import { AuthContext } from "../../context/Auth/AuthContext"; import { AuthContext } from "../../context/Auth/AuthContext"
import { green } from "@material-ui/core/colors"; import { green } from "@material-ui/core/colors"
import { import {
Button, Button,
CircularProgress, CircularProgress,
Divider, Divider,
IconButton, IconButton,
makeStyles, makeStyles,
} from "@material-ui/core"; } from "@material-ui/core"
import { import {
AccessTime, AccessTime,
Block, Block,
@ -20,20 +20,20 @@ import {
DoneAll, DoneAll,
ExpandMore, ExpandMore,
GetApp, GetApp,
} from "@material-ui/icons"; } from "@material-ui/icons"
import MarkdownWrapper from "../MarkdownWrapper"; import MarkdownWrapper from "../MarkdownWrapper"
import VcardPreview from "../VcardPreview"; import VcardPreview from "../VcardPreview"
import LocationPreview from "../LocationPreview"; import LocationPreview from "../LocationPreview"
import Audio from "../Audio"; import Audio from "../Audio"
import ModalImageCors from "../ModalImageCors"; import ModalImageCors from "../ModalImageCors"
import MessageOptionsMenu from "../MessageOptionsMenu"; import MessageOptionsMenu from "../MessageOptionsMenu"
import whatsBackground from "../../assets/wa-background.png"; import whatsBackground from "../../assets/wa-background.png"
import api from "../../services/api"; import api from "../../services/api"
import toastError from "../../errors/toastError"; import toastError from "../../errors/toastError"
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme) => ({
messagesListWrapper: { messagesListWrapper: {
@ -262,78 +262,78 @@ const useStyles = makeStyles((theme) => ({
backgroundColor: "inherit", backgroundColor: "inherit",
padding: 10, padding: 10,
}, },
})); }))
const reducer = (state, action) => { const reducer = (state, action) => {
if (action.type === "LOAD_MESSAGES") { if (action.type === "LOAD_MESSAGES") {
const messages = action.payload; const messages = action.payload
const newMessages = []; const newMessages = []
messages.forEach((message) => { messages.forEach((message) => {
const messageIndex = state.findIndex((m) => m.id === message.id); const messageIndex = state.findIndex((m) => m.id === message.id)
if (messageIndex !== -1) { if (messageIndex !== -1) {
state[messageIndex] = message; state[messageIndex] = message
} else { } else {
newMessages.push(message); newMessages.push(message)
} }
}); })
return [...newMessages, ...state]; return [...newMessages, ...state]
} }
if (action.type === "ADD_MESSAGE") { if (action.type === "ADD_MESSAGE") {
const newMessage = action.payload; const newMessage = action.payload
const messageIndex = state.findIndex((m) => m.id === newMessage.id); const messageIndex = state.findIndex((m) => m.id === newMessage.id)
if (messageIndex !== -1) { if (messageIndex !== -1) {
state[messageIndex] = newMessage; state[messageIndex] = newMessage
} else { } else {
state.push(newMessage); state.push(newMessage)
} }
return [...state]; return [...state]
} }
if (action.type === "UPDATE_MESSAGE") { if (action.type === "UPDATE_MESSAGE") {
const messageToUpdate = action.payload; const messageToUpdate = action.payload
const messageIndex = state.findIndex((m) => m.id === messageToUpdate.id); const messageIndex = state.findIndex((m) => m.id === messageToUpdate.id)
if (messageIndex !== -1) { if (messageIndex !== -1) {
state[messageIndex] = messageToUpdate; state[messageIndex] = messageToUpdate
} }
return [...state]; return [...state]
} }
if (action.type === "RESET") { if (action.type === "RESET") {
return []; return []
}
} }
};
const MessagesList = ({ ticketId, isGroup }) => { const MessagesList = ({ ticketId, isGroup }) => {
const classes = useStyles(); const classes = useStyles()
const [messagesList, dispatch] = useReducer(reducer, []); const [messagesList, dispatch] = useReducer(reducer, [])
const [pageNumber, setPageNumber] = useState(1); const [pageNumber, setPageNumber] = useState(1)
const [hasMore, setHasMore] = useState(false); const [hasMore, setHasMore] = useState(false)
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false)
const lastMessageRef = useRef(); const lastMessageRef = useRef()
const [selectedMessage, setSelectedMessage] = useState({}); const [selectedMessage, setSelectedMessage] = useState({})
const [anchorEl, setAnchorEl] = useState(null); const [anchorEl, setAnchorEl] = useState(null)
const messageOptionsMenuOpen = Boolean(anchorEl); const messageOptionsMenuOpen = Boolean(anchorEl)
const currentTicketId = useRef(ticketId); const currentTicketId = useRef(ticketId)
const [sendSeen, setSendSeen] = useState(false) const [sendSeen, setSendSeen] = useState(false)
const { user } = useContext(AuthContext); const { user } = useContext(AuthContext)
useEffect(() => { useEffect(() => {
dispatch({ type: "RESET" }); dispatch({ type: "RESET" })
setPageNumber(1); setPageNumber(1)
currentTicketId.current = ticketId; currentTicketId.current = ticketId
}, [ticketId]); }, [ticketId])
useEffect(() => { useEffect(() => {
@ -359,7 +359,7 @@ const MessagesList = ({ ticketId, isGroup }) => {
try { try {
const { data } = await api.get("/messages/" + ticketId, { const { data } = await api.get("/messages/" + ticketId, {
params: { pageNumber }, params: { pageNumber },
}); })
setSendSeen(false) setSendSeen(false)
@ -382,116 +382,116 @@ const MessagesList = ({ ticketId, isGroup }) => {
} }
} catch (err) { } catch (err) {
setLoading(false); setLoading(false)
toastError(err); toastError(err)
} }
}; }
sendSeenMessage(); sendSeenMessage()
}, 500); }, 500)
return () => { return () => {
clearTimeout(delayDebounceFn); clearTimeout(delayDebounceFn)
}; }
}, [sendSeen, pageNumber, ticketId, user.id]); }, [sendSeen, pageNumber, ticketId, user.id])
useEffect(() => { useEffect(() => {
setLoading(true); setLoading(true)
const delayDebounceFn = setTimeout(() => { const delayDebounceFn = setTimeout(() => {
const fetchMessages = async () => { const fetchMessages = async () => {
try { try {
const { data } = await api.get("/messages/" + ticketId, { const { data } = await api.get("/messages/" + ticketId, {
params: { pageNumber }, params: { pageNumber },
}); })
if (currentTicketId.current === ticketId) { if (currentTicketId.current === ticketId) {
dispatch({ type: "LOAD_MESSAGES", payload: data.messages }); dispatch({ type: "LOAD_MESSAGES", payload: data.messages })
setHasMore(data.hasMore); setHasMore(data.hasMore)
setLoading(false); setLoading(false)
} }
if (pageNumber === 1 && data.messages.length > 1) { if (pageNumber === 1 && data.messages.length > 1) {
scrollToBottom(); scrollToBottom()
} }
} catch (err) { } catch (err) {
setLoading(false); setLoading(false)
toastError(err); toastError(err)
} }
}; }
fetchMessages(); fetchMessages()
}, 500); }, 500)
return () => { return () => {
clearTimeout(delayDebounceFn); clearTimeout(delayDebounceFn)
}; }
}, [pageNumber, ticketId]); }, [pageNumber, ticketId])
useEffect(() => { 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)); socket.on("connect", () => socket.emit("joinChatBox", ticketId))
socket.on("appMessage", (data) => { socket.on("appMessage", (data) => {
if (data.action === "create") { if (data.action === "create") {
dispatch({ type: "ADD_MESSAGE", payload: data.message }); dispatch({ type: "ADD_MESSAGE", payload: data.message })
scrollToBottom(); scrollToBottom()
} }
if (data.action === "update") { if (data.action === "update") {
dispatch({ type: "UPDATE_MESSAGE", payload: data.message }); dispatch({ type: "UPDATE_MESSAGE", payload: data.message })
} }
}); })
return () => { return () => {
socket.disconnect(); socket.disconnect()
}; }
}, [ticketId]); }, [ticketId])
const loadMore = () => { const loadMore = () => {
setPageNumber((prevPageNumber) => prevPageNumber + 1); setPageNumber((prevPageNumber) => prevPageNumber + 1)
}; }
const scrollToBottom = () => { const scrollToBottom = () => {
if (lastMessageRef.current) { if (lastMessageRef.current) {
setSendSeen(true) setSendSeen(true)
lastMessageRef.current.scrollIntoView({}); lastMessageRef.current.scrollIntoView({})
} }
}; }
const handleScroll = (e) => { const handleScroll = (e) => {
if (!hasMore) return; if (!hasMore) return
const { scrollTop } = e.currentTarget; const { scrollTop } = e.currentTarget
if (scrollTop === 0) { if (scrollTop === 0) {
document.getElementById("messagesList").scrollTop = 1; document.getElementById("messagesList").scrollTop = 1
} }
if (loading) { if (loading) {
return; return
} }
if (scrollTop < 50) { if (scrollTop < 50) {
loadMore(); loadMore()
}
} }
};
const handleOpenMessageOptionsMenu = (e, message) => { const handleOpenMessageOptionsMenu = (e, message) => {
setAnchorEl(e.currentTarget); setAnchorEl(e.currentTarget)
setSelectedMessage(message); setSelectedMessage(message)
}; }
const handleCloseMessageOptionsMenu = (e) => { const handleCloseMessageOptionsMenu = (e) => {
setAnchorEl(null); setAnchorEl(null)
}; }
// const checkMessageMedia = (message) => { // const checkMessageMedia = (message) => {
// if (message.mediaType === "image") { // if (message.mediaType === "image") {
@ -548,8 +548,6 @@ const MessagesList = ({ ticketId, isGroup }) => {
return <LocationPreview image={imageLocation} link={linkLocation} description={descriptionLocation} /> return <LocationPreview image={imageLocation} link={linkLocation} description={descriptionLocation} />
} }
else if (message.mediaType === "vcard") { else if (message.mediaType === "vcard") {
//console.log("vcard")
//console.log(message)
let array = message.body.split("\n") let array = message.body.split("\n")
let obj = [] let obj = []
let contact = "" let contact = ""
@ -567,23 +565,44 @@ const MessagesList = ({ ticketId, isGroup }) => {
} }
return <VcardPreview contact={contact} numbers={obj[0]?.number} /> return <VcardPreview contact={contact} numbers={obj[0]?.number} />
} }
/*else if (message.mediaType === "multi_vcard") { else if (message.mediaType === "multi_vcard") {
console.log("multi_vcard")
console.log(message)
if (message.body !== null && message.body !== "") { if (message.body !== null && message.body !== "") {
let newBody = JSON.parse(message.body) let newBody = JSON.parse(message.body)
let multi_vcard = newBody.map(v => {
let array = v.split("\n")
let obj = []
let contact = ""
for (let index = 0; index < array.length; index++) {
const v = array[index]
let values = v.split(":")
for (let ind = 0; ind < values.length; ind++) {
if (values[ind].indexOf("+") !== -1) {
obj.push({ number: values[ind] })
}
if (values[ind].indexOf("FN") !== -1) {
contact = values[ind + 1]
}
}
}
return { name: contact, number: obj[0]?.number }
})
return ( return (
<> <>
{ {
newBody.map(v => ( multi_vcard.map((v, index) => (
<VcardPreview contact={v.name} numbers={v.number} /> <>
<VcardPreview contact={v.name} numbers={v.number} multi_vCard={true} id={v.number} />
{((index + 1) <= multi_vcard.length - 1) && <Divider />}
</>
)) ))
} }
</> </>
) )
} else return (<></>) } else return (<></>)
}*/ }
else if (/^.*\.(jpe?g|png|gif)?$/i.exec(message.mediaUrl) && message.mediaType === "image") { else if (/^.*\.(jpe?g|png|gif)?$/i.exec(message.mediaUrl) && message.mediaType === "image") {
return <ModalImageCors imageUrl={message.mediaUrl} /> return <ModalImageCors imageUrl={message.mediaUrl} />
} else if (message.mediaType === "audio") { } else if (message.mediaType === "audio") {
@ -614,22 +633,22 @@ const MessagesList = ({ ticketId, isGroup }) => {
</> </>
) )
} }
}; }
const renderMessageAck = (message) => { const renderMessageAck = (message) => {
if (message.ack === 0) { if (message.ack === 0) {
return <AccessTime fontSize="small" className={classes.ackIcons} />; return <AccessTime fontSize="small" className={classes.ackIcons} />
} }
if (message.ack === 1) { if (message.ack === 1) {
return <Done fontSize="small" className={classes.ackIcons} />; return <Done fontSize="small" className={classes.ackIcons} />
} }
if (message.ack === 2) { if (message.ack === 2) {
return <DoneAll fontSize="small" className={classes.ackIcons} />; return <DoneAll fontSize="small" className={classes.ackIcons} />
} }
if (message.ack === 3 || message.ack === 4) { if (message.ack === 3 || message.ack === 4) {
return <DoneAll fontSize="small" className={classes.ackDoneAllIcon} />; return <DoneAll fontSize="small" className={classes.ackDoneAllIcon} />
}
} }
};
const renderDailyTimestamps = (message, index) => { const renderDailyTimestamps = (message, index) => {
if (index === 0) { if (index === 0) {
@ -642,12 +661,12 @@ const MessagesList = ({ ticketId, isGroup }) => {
{format(parseISO(messagesList[index].createdAt), "dd/MM/yyyy")} {format(parseISO(messagesList[index].createdAt), "dd/MM/yyyy")}
</div> </div>
</span> </span>
); )
} }
if (index < messagesList.length - 1) { if (index < messagesList.length - 1) {
let messageDay = parseISO(messagesList[index].createdAt); let messageDay = parseISO(messagesList[index].createdAt)
let previousMessageDay = parseISO(messagesList[index - 1].createdAt); let previousMessageDay = parseISO(messagesList[index - 1].createdAt)
if (!isSameDay(messageDay, previousMessageDay)) { if (!isSameDay(messageDay, previousMessageDay)) {
@ -660,14 +679,14 @@ const MessagesList = ({ ticketId, isGroup }) => {
{format(parseISO(messagesList[index].createdAt), "dd/MM/yyyy")} {format(parseISO(messagesList[index].createdAt), "dd/MM/yyyy")}
</div> </div>
</span> </span>
); )
} }
} }
if (index === messagesList.length - 1) { if (index === messagesList.length - 1) {
let messageDay = parseISO(messagesList[index].createdAt); let messageDay = parseISO(messagesList[index].createdAt)
let previousMessageDay = parseISO(messagesList[index - 1].createdAt); let previousMessageDay = parseISO(messagesList[index - 1].createdAt)
return ( return (
<> <>
@ -687,24 +706,24 @@ const MessagesList = ({ ticketId, isGroup }) => {
style={{ float: "left", clear: "both" }} style={{ float: "left", clear: "both" }}
/> />
</> </>
); )
}
} }
};
const renderMessageDivider = (message, index) => { const renderMessageDivider = (message, index) => {
if (index < messagesList.length && index > 0) { if (index < messagesList.length && index > 0) {
let messageUser = messagesList[index].fromMe; let messageUser = messagesList[index].fromMe
let previousMessageUser = messagesList[index - 1].fromMe; let previousMessageUser = messagesList[index - 1].fromMe
if (messageUser !== previousMessageUser) { if (messageUser !== previousMessageUser) {
return ( return (
<span style={{ marginTop: 16 }} key={`divider-${message.id}`}></span> <span style={{ marginTop: 16 }} key={`divider-${message.id}`}></span>
); )
}
} }
} }
};
const renderQuotedMessage = (message) => { const renderQuotedMessage = (message) => {
return ( return (
@ -727,8 +746,8 @@ const MessagesList = ({ ticketId, isGroup }) => {
{message.quotedMsg?.body} {message.quotedMsg?.body}
</div> </div>
</div> </div>
); )
}; }
// const renderMessages = () => { // const renderMessages = () => {
// if (messagesList.length > 0) { // if (messagesList.length > 0) {
@ -837,7 +856,7 @@ const MessagesList = ({ ticketId, isGroup }) => {
</span> </span>
)} )}
{(message.mediaUrl || message.mediaType === "location" || message.mediaType === "vcard" {(message.mediaUrl || message.mediaType === "location" || message.mediaType === "vcard"
//|| message.mediaType === "multi_vcard" || message.mediaType === "multi_vcard"
) && checkMessageMedia(message)} ) && checkMessageMedia(message)}
<div className={classes.textContentItem}> <div className={classes.textContentItem}>
{message.quotedMsg && renderQuotedMessage(message)} {message.quotedMsg && renderQuotedMessage(message)}
@ -896,7 +915,7 @@ const MessagesList = ({ ticketId, isGroup }) => {
} else { } else {
return <div>Say hello to your new contact!</div> return <div>Say hello to your new contact!</div>
} }
}; }
return ( return (
<div className={classes.messagesListWrapper}> <div className={classes.messagesListWrapper}>
@ -919,7 +938,7 @@ const MessagesList = ({ ticketId, isGroup }) => {
</div> </div>
)} )}
</div> </div>
); )
}; }
export default MessagesList; export default MessagesList

View File

@ -1,25 +1,25 @@
import React, { useEffect, useState, useContext } from 'react'; import React, { useEffect, useState, useContext } from 'react'
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom"
import toastError from "../../errors/toastError"; import toastError from "../../errors/toastError"
import api from "../../services/api"; import api from "../../services/api"
import Avatar from "@material-ui/core/Avatar"; import Avatar from "@material-ui/core/Avatar"
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography"
import Grid from "@material-ui/core/Grid"; import Grid from "@material-ui/core/Grid"
import { AuthContext } from "../../context/Auth/AuthContext"; import { AuthContext } from "../../context/Auth/AuthContext"
import { Button, Divider, } from "@material-ui/core"; import { Button, Divider, } from "@material-ui/core"
const VcardPreview = ({ contact, numbers }) => { const VcardPreview = ({ contact, numbers, multi_vCard }) => {
const history = useHistory(); const history = useHistory()
const { user } = useContext(AuthContext); const { user } = useContext(AuthContext)
const [selectedContact, setContact] = useState({ const [selectedContact, setContact] = useState({
name: "", name: "",
number: 0, number: 0,
profilePicUrl: "" profilePicUrl: ""
}); })
useEffect(() => { useEffect(() => {
const delayDebounceFn = setTimeout(() => { const delayDebounceFn = setTimeout(() => {
@ -32,18 +32,19 @@ const VcardPreview = ({ contact, numbers }) => {
email: "" email: ""
} }
const { data } = await api.post("/contact", contactObj); const { data } = await api.post("/contact", contactObj)
setContact(data) setContact(data)
} catch (err) { } catch (err) {
console.log(err) console.log(err)
toastError(err); toastError(err)
} }
}; }
fetchContacts(); fetchContacts()
}, 500); }, 500)
return () => clearTimeout(delayDebounceFn); return () => clearTimeout(delayDebounceFn)
}, [contact, numbers]); }, [contact, numbers])
const handleNewChat = async () => { const handleNewChat = async () => {
try { try {
@ -51,10 +52,10 @@ const VcardPreview = ({ contact, numbers }) => {
contactId: selectedContact.id, contactId: selectedContact.id,
userId: user.id, userId: user.id,
status: "open", status: "open",
}); })
history.push(`/tickets/${ticket.id}`); history.push(`/tickets/${ticket.id}`)
} catch (err) { } catch (err) {
toastError(err); toastError(err)
} }
} }
@ -73,19 +74,23 @@ const VcardPreview = ({ contact, numbers }) => {
</Typography> </Typography>
</Grid> </Grid>
<Grid item xs={12}> <Grid item xs={12}>
<Divider /> {!multi_vCard && <Divider />}
<Button <Button
fullWidth fullWidth
color="primary" color="primary"
onClick={handleNewChat} onClick={handleNewChat}
disabled={!selectedContact.number} disabled={!selectedContact.number}
>Conversar</Button> >Conversar</Button>
{/* {multi_vCard && <Divider />} */}
</Grid> </Grid>
</Grid> </Grid>
</div> </div>
</> </>
); )
}; }
export default VcardPreview; export default VcardPreview

View File

@ -1,37 +1,24 @@
import { Box } from '@material-ui/core'; import { Box } from '@material-ui/core';
import React from 'react'; import React from 'react';
import FiberManualRecordIcon from '@material-ui/icons/FiberManualRecord'; import FiberManualRecordIcon from '@material-ui/icons/FiberManualRecord';
import { PieChart as RechartsPieChart, Pie, Sector, Cell, ResponsiveContainer } from 'recharts'; import { PieChart as RechartsPieChart, Pie, Cell, ResponsiveContainer, Tooltip } from 'recharts';
import Title from './Title'; import Title from './Title';
const dataExample = [ const generateDataExample = (amount) => {
{ const arr = []
"id": 3366, for (let i = 1; i <= amount; i++) {
"name": "FINALIZADO", arr.push({
"count": 5 "id": i,
}, "name": `Exemplo ${i}`,
{ "count": Math.floor(Math.random() * 10 + 2)
"id": 3369, })
"name": "LEMBRETE", }
"count": 1
}, return arr
{ }
"id": 3367,
"name": "EXEMPLO", const dataExample = generateDataExample(20)
"count": 3
},
{
"id": 3364,
"name": "EXEMPLO 2",
"count": 3
},
{
"id": 3364,
"name": "EXEMPLO 3",
"count": 6
},
]
const COLORS = [ const COLORS = [
'#0088FE', // Azul escuro '#0088FE', // Azul escuro
@ -44,12 +31,22 @@ const COLORS = [
'#C0FFC0', // Verde Claro '#C0FFC0', // Verde Claro
'#C4E538', // Verde-amarelo vibrante '#C4E538', // Verde-amarelo vibrante
'#A2A2A2', // Cinza claro '#A2A2A2', // Cinza claro
];; '#FFF700', // Amarelo Canário
'#FF69B4', // Rosa Flamingo
'#87CEEB', // Azul Celeste
'#228B22', // Verde Esmeralda
'#9B59B6', // Roxo Ametista
'#FF9933', // Laranja Tangerina
'#FF7F50', // Coral Vivo
'#00CED1', // Verde Água
'#000080', // Azul Marinho
'#FFDB58', // Amarelo Mostarda
];
const RADIAN = Math.PI / 180; const RADIAN = Math.PI / 180;
const renderCustomizedLabel = ({ cx, cy, midAngle, innerRadius, outerRadius, count }) => { const renderCustomizedLabel = ({ cx, cy, midAngle, innerRadius, outerRadius, count }) => {
const radius = innerRadius + (outerRadius - innerRadius) * 0.75; const radius = innerRadius + (outerRadius - innerRadius) * 0.80;
const x = cx + radius * Math.cos(-midAngle * RADIAN); const x = cx + radius * Math.cos(-midAngle * RADIAN);
const y = cy + radius * Math.sin(-midAngle * RADIAN); const y = cy + radius * Math.sin(-midAngle * RADIAN);
@ -70,10 +67,37 @@ const renderCustomizedLabel = ({ cx, cy, midAngle, innerRadius, outerRadius, cou
*/ */
const PieChart = ({ data = dataExample }) => { const PieChart = ({ data = dataExample }) => {
return ( return (
<Box width="100%" height="100%" position="relative" display="flex"> <Box
width="100%"
height="100%"
position="relative"
display="flex"
sx={{ overflowY: "scroll" }}
>
<Box width="100%" height="100%" position="sticky" top="0" zIndex={1000}>
<Box sx={{ position: "absolute" }}> <Box sx={{ position: "absolute" }}>
<Title>Tickets encerramento</Title> <Title>Tickets encerramento</Title>
</Box> </Box>
<ResponsiveContainer width="100%" height="100%">
<RechartsPieChart width={400} height={400}>
<Pie
data={data}
cx="25%"
cy="60%"
labelLine={false}
label={renderCustomizedLabel}
outerRadius={100}
fill="#8884d8"
dataKey="count"
>
{data.map((entry, index) => (
<Cell key={`cell-${entry.id}`} fill={COLORS[index % COLORS.length]} />
))}
</Pie>
<Tooltip />
</RechartsPieChart>
</ResponsiveContainer>
</Box>
<Box <Box
component="ul" component="ul"
sx={{ sx={{
@ -81,7 +105,10 @@ const PieChart = ({ data = dataExample }) => {
top: 0, right: 0, top: 0, right: 0,
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
gap: "4px" gap: "4px",
maxWidth: "60%",
minWidth: "50%",
zIndex: 0,
}}> }}>
{data.map((entry, index) => { {data.map((entry, index) => {
return ( return (
@ -99,26 +126,6 @@ const PieChart = ({ data = dataExample }) => {
) )
})} })}
</Box> </Box>
<Box width="100%" height="100%" alignSelf="flex-end">
<ResponsiveContainer width="100%" height="100%">
<RechartsPieChart width={400} height={400}>
<Pie
data={data}
cx="40%"
cy="60%"
labelLine={false}
label={renderCustomizedLabel}
outerRadius={100}
fill="#8884d8"
dataKey="count"
>
{data.map((entry, index) => (
<Cell key={`cell-${entry.id}`} fill={COLORS[index % COLORS.length]} />
))}
</Pie>
</RechartsPieChart>
</ResponsiveContainer>
</Box>
</Box > </Box >
); );

View File

@ -461,7 +461,6 @@ const Report = () => {
// Get from report type option // Get from report type option
const reportTypeValue = (data) => { const reportTypeValue = (data) => {
console.log('DATA: ', data)
let type = '1' let type = '1'
if (data === '1') type = 'default' if (data === '1') type = 'default'
if (data === '2') type = 'synthetic' if (data === '2') type = 'synthetic'