Merge branch 'ominihit_hit' into dialogflow_ansata3
commit
77b7ed393f
|
@ -211,7 +211,8 @@ app.post('/api/session', async function (req, res) {
|
|||
|
||||
session_num = numbered_sessions.map((e) => parseInt((e.name.split('->')[e.name.split('->').length - 1]).trim().match(/\d+/)[0]))
|
||||
|
||||
console.log('session_num', session_num)
|
||||
console.log('session_num', session_num)
|
||||
|
||||
}
|
||||
|
||||
let index = 1;
|
||||
|
|
|
@ -19,8 +19,8 @@ const express = require('express');
|
|||
const FormData = require('form-data');
|
||||
|
||||
// const { MessageMedia } = require('./node_modules/whatsapp-web.js/src/structures');
|
||||
let whatsappWebGlobalPath = path.join(process.env.NODE_PATH, 'whatsapp-web.js', '/src/structures');
|
||||
whatsappWebGlobalPath = whatsappWebGlobalPath.replace(':','')
|
||||
let whatsappWebGlobalPath = path.join(process.env.NODE_PATH, 'whatsapp-web.js', '/src/structures');
|
||||
whatsappWebGlobalPath = whatsappWebGlobalPath.replace(':', '')
|
||||
|
||||
console.log('whatsappWebGlobalPath: ', whatsappWebGlobalPath)
|
||||
console.log('process.env.NODE_PATH: ', process.env.NODE_PATH)
|
||||
|
@ -178,17 +178,22 @@ client.on("qr", async qr => {
|
|||
|
||||
asking_qrcode = true
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
|
||||
dbcc.query("UPDATE Whatsapps SET qrcode = ?, status = ?, retries = ? where id = ?", [qr, 'qrcode', 0, process.env.WHATSAPP_ID],
|
||||
dbcc.query("UPDATE Whatsapps SET qrcode = ?, status = ?, retries = ? where id = ?", [qr, 'qrcode', 0, process.env.WHATSAPP_ID],
|
||||
|
||||
function (err, result) {
|
||||
if (err)
|
||||
console.log("ERROR: " + err);
|
||||
function (err, result) {
|
||||
|
||||
// else
|
||||
// console.log('myslq result: ', result);
|
||||
});
|
||||
if (err) {
|
||||
console.log("ERROR: " + err);
|
||||
reject(err)
|
||||
}
|
||||
else {
|
||||
resolve(result)
|
||||
}
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
let url = process.env.CLIENT_URL + '/whatsapp/connection/qrcode'
|
||||
|
||||
|
@ -271,15 +276,25 @@ client.on("ready", async () => {
|
|||
|
||||
|
||||
|
||||
dbcc.query("UPDATE Whatsapps SET qrcode = ?, status = ?, retries = ?, number = ? where id = ?", ["", 'CONNECTED', 0, client.info["wid"]["user"], process.env.WHATSAPP_ID],
|
||||
await new Promise((resolve, reject) => {
|
||||
|
||||
dbcc.query("UPDATE Whatsapps SET qrcode = ?, status = ?, retries = ?, number = ? where id = ?", ["", 'CONNECTED', 0, client.info["wid"]["user"], process.env.WHATSAPP_ID],
|
||||
|
||||
function (err, result) {
|
||||
|
||||
if (err) {
|
||||
console.log("ERROR: " + err);
|
||||
reject(err)
|
||||
}
|
||||
else {
|
||||
resolve(result)
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
function (err, result) {
|
||||
if (err)
|
||||
console.log("ERROR: " + err);
|
||||
|
||||
// else
|
||||
// console.log('myslq result: ', result);
|
||||
});
|
||||
|
||||
let url = process.env.CLIENT_URL + '/whatsapp/connection/qrcode'
|
||||
|
||||
|
@ -384,7 +399,7 @@ client.on("message_ack", async (msg, ack) => {
|
|||
});
|
||||
|
||||
socketIo.on('send_message', async data => {
|
||||
|
||||
|
||||
console.log('#')
|
||||
console.log('--------------> send_message from number: ', mobileuid);
|
||||
console.log('--------------> send_message to number: ', data.msg.number);
|
||||
|
@ -400,7 +415,7 @@ socketIo.on('send_message', async data => {
|
|||
|
||||
|
||||
socketIo.on('send_media', async data => {
|
||||
|
||||
|
||||
console.log('#')
|
||||
console.log('--------------> send_message from number: ', mobileuid);
|
||||
console.log('--------------> send_message to number: ', data.msg.number);
|
||||
|
@ -414,7 +429,7 @@ socketIo.on('send_media', async data => {
|
|||
|
||||
if (media && !media.filename)
|
||||
media.filename = data.msg.media.filename
|
||||
|
||||
|
||||
const sentMessage = await client.sendMessage(data.msg.number, media, { sendAudioAsVoice: data.msg.sendAudioAsVoice });
|
||||
|
||||
// const fullFilename = process.cwd() + process.env.MEDIA_DOWNLOAD_IN + data.msg.media.filename;
|
||||
|
@ -590,6 +605,37 @@ app.post('/api/restore', async (req, res) => {
|
|||
res.status(200).json({ message: "ok" });
|
||||
})
|
||||
|
||||
app.post('/api/sendSeen', async (req, res) => {
|
||||
|
||||
let stat
|
||||
|
||||
const { number } = req.body
|
||||
|
||||
try {
|
||||
|
||||
stat = await client.getState();
|
||||
|
||||
// await syncUnreadMessages(client)
|
||||
|
||||
const wbotChat = await client.getChatById(number);
|
||||
|
||||
wbotChat.sendSeen();
|
||||
|
||||
// const chatMessages = await wbotChat.fetchMessages({ limit: 100 });
|
||||
|
||||
// console.log('=============> wbotChat: ', chatMessages)
|
||||
|
||||
} catch (err) {
|
||||
|
||||
let terr = err.message;
|
||||
|
||||
stat = (terr.search('Session closed') > -1 ? 'SESSIONCLOSED' : 'UNKNOWN')
|
||||
|
||||
}
|
||||
|
||||
res.status(200).json({ message: "ok" });
|
||||
})
|
||||
|
||||
app.get('/api/connection/status', async (req, res) => {
|
||||
|
||||
let stat
|
||||
|
@ -621,6 +667,8 @@ const syncUnreadMessages = async (wbot) => {
|
|||
/* eslint-disable no-await-in-loop */
|
||||
for (const chat of chats) {
|
||||
|
||||
// console.log('chat: ', chat)
|
||||
|
||||
if (chat.unreadCount > 0) {
|
||||
|
||||
const unreadMessages = await chat.fetchMessages({
|
||||
|
@ -685,14 +733,13 @@ const getWbotMessage = async (messageId, number, limit,) => {
|
|||
|
||||
async function whatsappMonitor(newState, omnihit_url, data) {
|
||||
|
||||
dbcc.query("UPDATE Whatsapps SET status = ? where id = ?", [newState, process.env.WHATSAPP_ID],
|
||||
function (err, result) {
|
||||
if (err)
|
||||
console.log("ERROR: " + err);
|
||||
const whatsapp = await whatsappUpdateStatus(newState)
|
||||
|
||||
// else
|
||||
// console.log('myslq result: ', result);
|
||||
});
|
||||
if (whatsapp && whatsapp.affectedRows) {
|
||||
console.log('whatsapp status update affectedRows: ', whatsapp.affectedRows)
|
||||
}
|
||||
|
||||
// console.log(' whatsappwhatsappwhatsappwhatsapp: ', whatsapp)
|
||||
|
||||
|
||||
try {
|
||||
|
@ -702,6 +749,23 @@ async function whatsappMonitor(newState, omnihit_url, data) {
|
|||
}
|
||||
}
|
||||
|
||||
async function whatsappUpdateStatus(newState) {
|
||||
return await new Promise((resolve, reject) => {
|
||||
|
||||
dbcc.query("UPDATE Whatsapps SET status = ? where id = ?", [newState, process.env.WHATSAPP_ID],
|
||||
function (err, result) {
|
||||
if (err) {
|
||||
console.log("ERROR: " + err);
|
||||
reject(err);
|
||||
}
|
||||
else {
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
async function handleMessage(msg) {
|
||||
|
||||
console.log('Entrou no message_create');
|
||||
|
@ -709,7 +773,7 @@ async function handleMessage(msg) {
|
|||
let msgContact = null;
|
||||
let media = null;
|
||||
|
||||
if (msg.fromMe) {
|
||||
if (msg.fromMe) {
|
||||
|
||||
msgContact = await client.getContactById(msg.to);
|
||||
|
||||
|
@ -740,7 +804,7 @@ async function handleMessage(msg) {
|
|||
quotedMsg: quotedMsg ? quotedMsg.id.id : null,
|
||||
media: media
|
||||
};
|
||||
|
||||
|
||||
|
||||
socketIo.emit("message_create", data);
|
||||
|
||||
|
@ -868,6 +932,14 @@ async function monitor() {
|
|||
|
||||
console.log(`WHATSAPP_ID: ${process.env.WHATSAPP_ID} | CLIENT MOBILEUID: ${mobileuid} | NAME: ${process.env.MOBILENAME} | ENV MOBILEUID: ${process.env.MOBILEUID} | STATUS: ${stat}`)
|
||||
|
||||
if (stat && stat === 'CONNECTED') {
|
||||
|
||||
const result = await whatsappUpdateStatus('CONNECTED')
|
||||
|
||||
if (result)
|
||||
console.log(`Update status to CONNECTED WHATSAPP_ID: ${process.env.WHATSAPP_ID} => result.affectedRows: ${result.affectedRows}`)
|
||||
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
//new Date(new Date() + 'UTC')
|
||||
|
|
|
@ -107,6 +107,7 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
|||
number: Yup.string()
|
||||
.required()
|
||||
.matches(/^\d+$/, "Invalid number format. Only numbers is allowed.")
|
||||
.matches(/^55\d+$/, "The number must start with 55.")
|
||||
});
|
||||
|
||||
try {
|
||||
|
@ -173,10 +174,9 @@ export const update = async (
|
|||
|
||||
const schema = Yup.object().shape({
|
||||
name: Yup.string(),
|
||||
number: Yup.string().matches(
|
||||
/^\d+$/,
|
||||
"Invalid number format. Only numbers is allowed."
|
||||
)
|
||||
number: Yup.string()
|
||||
.matches(/^\d+$/,"Invalid number format. Only numbers is allowed.")
|
||||
.matches(/^55\d+$/, "The number must start with 55.")
|
||||
});
|
||||
|
||||
try {
|
||||
|
|
|
@ -14,217 +14,139 @@ import SendWhatsAppMessage from "../services/WbotServices/SendWhatsAppMessage";
|
|||
import { Op, where, Sequelize } from "sequelize";
|
||||
import ShowTicketServiceByContactId from "../services/TicketServices/ShowTicketServiceByContactId";
|
||||
import hitPortalMonitoring from "../helpers/HitPortalMonitoring";
|
||||
import { sendDialogflowAwswer, verifyContact } from "../services/WbotServices/wbotMessageListener";
|
||||
import CheckIsValidContact from "../services/WbotServices/CheckIsValidContact";
|
||||
import Contact from "../models/Contact";
|
||||
import GetProfilePicUrl from "../services/WbotServices/GetProfilePicUrl";
|
||||
import CreateContactService from "../services/ContactServices/CreateContactService";
|
||||
import { resourceUsage } from "process";
|
||||
import FindOrCreateTicketServiceBot from "../services/TicketServices/FindOrCreateTicketServiceBot";
|
||||
|
||||
|
||||
|
||||
// type IndexQuery = {
|
||||
// centro_custo: string;
|
||||
// cod_web: string;
|
||||
// };
|
||||
|
||||
export const hit = async (req: Request, res: Response): Promise<Response> => {
|
||||
|
||||
// const {
|
||||
// centro_custo,
|
||||
// cod_web,
|
||||
// } = req.body as IndexQuery;
|
||||
|
||||
console.log('req.boy: ', req.body)
|
||||
console.log('req.boy: ', req.body['centro_custo'])
|
||||
console.log('ACTION: ', req.body['action'])
|
||||
console.log("req.body['cod_web']: ", req.body['cod_web'])
|
||||
console.log("req.body['action']: ", req.body['action'])
|
||||
console.log("req.body['phone']: ", req.body['phone'])
|
||||
console.log("req.body['name']: ", req.body['name'])
|
||||
|
||||
|
||||
if (req.headers["auth"] === '0424bd59b807674191e7d77572075f33') {
|
||||
|
||||
let contact = null
|
||||
let phone = req.body['phone']
|
||||
let name = req.body['name']
|
||||
|
||||
try {
|
||||
if (!phone) return res.status(200).json({ "message": "Ok" });
|
||||
|
||||
contact = await ContactByCustomField(req.body['centro_custo'])
|
||||
const regex = /^55/;
|
||||
|
||||
} catch (error) {
|
||||
phone = phone.match(/\d+/g).join('');
|
||||
|
||||
console.log('There was an error on try get centro_custo info: ', error)
|
||||
if (!regex.test(phone)) {
|
||||
phone = '55' + phone;
|
||||
}
|
||||
|
||||
if (phone.length < 7) return res.status(200).json({ "message": "Ok" });
|
||||
|
||||
let validNumber = await CheckIsValidContact(phone);
|
||||
|
||||
if (!validNumber) {
|
||||
return res.status(200).json({ "message": "Ok" });
|
||||
}
|
||||
|
||||
validNumber = req.body['cod_web']==='0001' ? validNumber : '5517988325936'
|
||||
|
||||
let contact = await Contact.findOne({ where: { number: validNumber } });
|
||||
// let contact = await Contact.findOne({ where: { number: '5517988325936' } });
|
||||
|
||||
if (!contact) {
|
||||
|
||||
const profilePicUrl = await GetProfilePicUrl(validNumber);
|
||||
|
||||
contact = await CreateContactService({
|
||||
name: name || phone,
|
||||
number: validNumber,
|
||||
profilePicUrl: profilePicUrl,
|
||||
});
|
||||
|
||||
const io = getIO();
|
||||
io.emit("contact", {
|
||||
action: "create",
|
||||
contact
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
let response: any = await hitPortalMonitoring({
|
||||
'params[n_chamado_web]': req.body['n_chamado_web'],
|
||||
'method': 'omnihit.consultachamado',
|
||||
})
|
||||
|
||||
if (!response || response.length == 0 || !contact) {
|
||||
console.log('Empty result from hit portal monitoring to n_chamado_web: ', req.body['n_chamado_web'])
|
||||
return res.status(200).json({ "message": "Ok" });
|
||||
}
|
||||
|
||||
const botInfo = await BotIsOnQueue('botqueue')
|
||||
|
||||
let ticket: any = await ShowTicketServiceByContactId(contact.id)
|
||||
|
||||
if (!ticket.dataValues.id) {
|
||||
|
||||
const defaultWhatsapp = await GetDefaultWhatsApp();
|
||||
|
||||
let ticket_obj: any = await FindOrCreateTicketServiceBot(
|
||||
contact,
|
||||
defaultWhatsapp.id!,
|
||||
0,
|
||||
);
|
||||
|
||||
ticket = ticket_obj.ticket
|
||||
}
|
||||
|
||||
|
||||
if (req.body['action'] === 'atdfechou') {
|
||||
if (ticket.id && ticket.status == 'pending') {
|
||||
|
||||
console.log('FECHOU')
|
||||
|
||||
try {
|
||||
|
||||
console.log('atdfechou ----------> THE CONTACT: ', contact)
|
||||
|
||||
if (contact) {
|
||||
|
||||
let data = req.body
|
||||
let str = ''
|
||||
let str2 = ''
|
||||
|
||||
// const exclude = ["action", "centro_custo", "n_chamado_web", "historico"];
|
||||
|
||||
// for (const key in data) {
|
||||
|
||||
// if (exclude.includes(`${key}`)) {
|
||||
// continue
|
||||
// }
|
||||
|
||||
// str += `${key.replace('hostname', 'cliente')}: ${data[key]}\n`
|
||||
|
||||
// }
|
||||
|
||||
str = `*Cliente*: ${contact['contact.name']}`
|
||||
|
||||
let historico = data['historico']
|
||||
|
||||
for (const key in historico) {
|
||||
|
||||
const hist = Object.keys(historico[key]);
|
||||
|
||||
hist.forEach((keys, index) => {
|
||||
|
||||
str2 += `*${keys}*: ${historico[key][keys]}\n`
|
||||
|
||||
});
|
||||
|
||||
str2 += '\n'
|
||||
|
||||
}
|
||||
|
||||
console.log('--------------> str: ', str)
|
||||
console.log('--------------> str2: ', str2)
|
||||
|
||||
const botInfo = await BotIsOnQueue('botqueue')
|
||||
|
||||
let ticket = await ShowTicketServiceByContactId(contact['contact.id'])
|
||||
|
||||
if (ticket.id && ticket.status == 'pending') {
|
||||
|
||||
await sendMessageHitMonitoring(`*Olá. Somos a TI Espaçolaser.*\nO chamado da sua loja ${contact['contact.name']} foi fechado pela operadora. Abaixo seguem informações sobre o incidente.\n\n*Situação do chamado na Operadora*\n\n*Incidente:*\n\n ${str}\n\n*Atualizações*:\n\n${str2}`, ticket);
|
||||
|
||||
}
|
||||
else if (!ticket.id) {
|
||||
|
||||
ticket = await CreateTicketService({ contactId: contact['contact.id'], status: 'open', userId: botInfo.userIdBot });
|
||||
|
||||
console.log('botInfo.botQueueId: ', botInfo.botQueueId)
|
||||
|
||||
await UpdateTicketService({ ticketData: { queueId: botInfo.botQueueId }, ticketId: ticket.id });
|
||||
|
||||
await sendMessageHitMonitoring(`*Olá. Somos a TI Espaçolaser.*\nO chamado da sua loja ${contact['contact.name']} foi fechado pela operadora. Abaixo seguem informações sobre o incidente.\n\n*Situação do chamado na Operadora*\n\n*Incidente:*\n\n ${str}\n\n*Atualizações*:\n\n${str2}`, ticket);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
|
||||
console.log(`Error on try sending the monitor message closed: `, error)
|
||||
|
||||
}
|
||||
}
|
||||
else if (req.body['action'] === 'atdatualizou') {
|
||||
|
||||
console.log('status: atdatualizou --------------> contact: ', contact)
|
||||
|
||||
if (contact) {
|
||||
|
||||
try {
|
||||
|
||||
let response = await hitPortalMonitoring(req.body['centro_custo'])
|
||||
|
||||
if (!response || response.length == 0) {
|
||||
console.log('Empty result from hit portal monitoring. Centro_de_custo: ', req.body['centro_custo'])
|
||||
return res.status(200).json({ "message": "Ok" });
|
||||
}
|
||||
|
||||
const botInfo = await BotIsOnQueue('botqueue')
|
||||
|
||||
let ticket = await ShowTicketServiceByContactId(contact['contact.id'])
|
||||
|
||||
if (ticket.id && ticket.status == 'pending') {
|
||||
|
||||
await sendMessageHitMonitoring(`*Olá. Somos a TI Espaçolaser.*\nAtualização do chamado para sua loja ${contact['contact.name']}. Abaixo seguem informações sobre o incidente para que possam acompanhar.\n\n*Situação do chamado na Operadora*\n\n*Incidente*:\n\n ${response[0].header}\n${response[0].body}`, ticket);
|
||||
|
||||
}
|
||||
else if (!ticket.id) {
|
||||
|
||||
ticket = await CreateTicketService({ contactId: contact['contact.id'], status: 'open', userId: botInfo.userIdBot });
|
||||
|
||||
console.log('botInfo.botQueueId: ', botInfo.botQueueId)
|
||||
|
||||
await UpdateTicketService({ ticketData: { queueId: botInfo.botQueueId }, ticketId: ticket.id });
|
||||
|
||||
await sendMessageHitMonitoring(`*Olá. Somos a TI Espaçolaser.*\nAtualização do chamado para sua loja ${contact['contact.name']}. Abaixo seguem informações sobre o incidente para que possam acompanhar.\n\n*Situação do chamado na Operadora*\n\n*Incidente*:\n\n ${response[0].header}\n${response[0].body}`, ticket);
|
||||
|
||||
}
|
||||
|
||||
|
||||
} catch (error) {
|
||||
|
||||
console.log(`Error on try sending the message monitor: `, error)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
await sendMessageHitMonitoring(response, ticket);
|
||||
|
||||
}
|
||||
else {
|
||||
else if (ticket.id && ticket.userId == botInfo.userIdBot) {
|
||||
|
||||
console.log('status: atdatabriu --------------> contact: ', contact)
|
||||
let queue = await ShowQueueService(botInfo.botQueueId);
|
||||
|
||||
if (contact) {
|
||||
await UpdateTicketService({ ticketData: { queueId: queue.id }, ticketId: ticket.id });
|
||||
|
||||
try {
|
||||
ticket = await ShowTicketService(ticket.id);
|
||||
|
||||
let response = await hitPortalMonitoring(req.body['centro_custo'])
|
||||
let msg: any = { type: 'chat', from: `${contact.number}@c.us`, body: '0' }
|
||||
|
||||
if (!response || response.length == 0) {
|
||||
console.log('Empty result from hit portal monitoring. Centro_de_custo: ', req.body['centro_custo'])
|
||||
return res.status(200).json({ "message": "Ok" });
|
||||
}
|
||||
await sendDialogflowAwswer(ticket.whatsappId, ticket, msg, contact, false);
|
||||
|
||||
const botInfo = await BotIsOnQueue('botqueue')
|
||||
|
||||
let ticket = await ShowTicketServiceByContactId(contact['contact.id'])
|
||||
|
||||
if (ticket.id && ticket.status == 'pending') {
|
||||
|
||||
await sendMessageHitMonitoring(`*Olá. Somos a TI Espaçolaser.*\nIdentificamos em nossos monitoramentos que há um problema na internet da sua loja ${contact['contact.name']} e já estamos resolvendo. Abaixo seguem informações sobre o incidente para que possam acompanhar.\n\n*Situação do chamado na Operadora*\n\n*Incidente*:\n\n ${response[0].header}\n${response[0].body}`, ticket);
|
||||
|
||||
}
|
||||
else if (!ticket.id) {
|
||||
|
||||
ticket = await CreateTicketService({ contactId: contact['contact.id'], status: 'open', userId: botInfo.userIdBot });
|
||||
|
||||
console.log('botInfo.botQueueId: ', botInfo.botQueueId)
|
||||
|
||||
await UpdateTicketService({ ticketData: { queueId: botInfo.botQueueId }, ticketId: ticket.id });
|
||||
|
||||
await sendMessageHitMonitoring(`*Olá. Somos a TI Espaçolaser.*\nIdentificamos em nossos monitoramentos que há um problema na internet da sua loja ${contact['contact.name']} e já estamos resolvendo. Abaixo seguem informações sobre o incidente para que possam acompanhar.\n\n*Situação do chamado na Operadora*\n\n*Incidente*:\n\n ${response[0].header}\n${response[0].body}`, ticket);
|
||||
|
||||
}
|
||||
|
||||
|
||||
} catch (error) {
|
||||
|
||||
console.log(`Error on try sending the message monitor: `, error)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
await sendMessageHitMonitoring(response, ticket);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
res.status(401).json({ "message": "Token Inválido!" });
|
||||
return res.status(401).json({ "message": "Token Inválido!" });
|
||||
}
|
||||
|
||||
|
||||
return res.status(200).json({ "message": "Ok" });
|
||||
|
||||
};
|
||||
|
||||
async function sendMessageHitMonitoring(msg: string, ticket: Ticket) {
|
||||
async function sendMessageHitMonitoring(msg: any, ticket: Ticket) {
|
||||
|
||||
if (msg && msg.length > 0) {
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import ShowTicketService from "../services/TicketServices/ShowTicketService";
|
|||
import DeleteWhatsAppMessage from "../services/WbotServices/DeleteWhatsAppMessage";
|
||||
import SendWhatsAppMedia from "../services/WbotServices/SendWhatsAppMedia";
|
||||
import SendWhatsAppMessage from "../services/WbotServices/SendWhatsAppMessage";
|
||||
|
||||
|
||||
type IndexQuery = {
|
||||
pageNumber: string;
|
||||
|
@ -19,12 +20,15 @@ type MessageData = {
|
|||
fromMe: boolean;
|
||||
read: boolean;
|
||||
quotedMsg?: Message;
|
||||
id?: string;
|
||||
};
|
||||
|
||||
export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||
const { ticketId } = req.params;
|
||||
const { pageNumber } = req.query as IndexQuery;
|
||||
|
||||
// console.log(':::::::::::::> TICKET ID: ', ticketId)
|
||||
|
||||
const { count, messages, ticket, hasMore } = await ListMessagesService({
|
||||
pageNumber,
|
||||
ticketId
|
||||
|
@ -34,24 +38,23 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
|
|||
|
||||
return res.json({ count, messages, ticket, hasMore });
|
||||
};
|
||||
|
||||
export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||
|
||||
|
||||
export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||
const { ticketId } = req.params;
|
||||
const { body, quotedMsg }: MessageData = req.body;
|
||||
const medias = req.files as Express.Multer.File[];
|
||||
|
||||
|
||||
const ticket = await ShowTicketService(ticketId);
|
||||
|
||||
console.log('TICKET ID: ', ticketId)
|
||||
console.log("TICKET ID: ", ticketId);
|
||||
|
||||
// SetTicketMessagesAsRead(ticket);
|
||||
|
||||
|
||||
if (medias) {
|
||||
await Promise.all(
|
||||
medias.map(async (media: Express.Multer.File) => {
|
||||
|
||||
console.log(`\n >>>>>>>>>> SENDING MESSAGE MEDIA
|
||||
medias.map(async (media: Express.Multer.File) => {
|
||||
console.log(
|
||||
`\n >>>>>>>>>> SENDING MESSAGE MEDIA
|
||||
Parcial ticket info and media:
|
||||
ticket.id: ${ticket.id}
|
||||
ticket.status: ${ticket.status}
|
||||
|
@ -61,13 +64,15 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
|||
ticket.contact.profilePicUrl: ${ticket.contact.profilePicUrl}
|
||||
ticket.user.id: ${ticket.user.id}
|
||||
ticket.user.name: ${ticket.user.name}
|
||||
media:`, media,'\n')
|
||||
media:`,
|
||||
media,
|
||||
"\n"
|
||||
);
|
||||
|
||||
await SendWhatsAppMedia({ media, ticket });
|
||||
})
|
||||
);
|
||||
} else {
|
||||
|
||||
console.log(`\n >>>>>>>>>> SENDING MESSAGE
|
||||
Parcial ticket info:
|
||||
ticket.id: ${ticket.id}
|
||||
|
@ -78,8 +83,7 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
|||
ticket.contact.name: ${ticket.contact.name}
|
||||
ticket.contact.profilePicUrl: ${ticket.contact.profilePicUrl}
|
||||
ticket.user.id: ${ticket.user.id}
|
||||
ticket.user.name: ${ticket.user.name}\n`)
|
||||
|
||||
ticket.user.name: ${ticket.user.name}\n`);
|
||||
|
||||
await SendWhatsAppMessage({ body, ticket, quotedMsg });
|
||||
}
|
||||
|
@ -102,4 +106,4 @@ export const remove = async (
|
|||
});
|
||||
|
||||
return res.send();
|
||||
};
|
||||
};
|
|
@ -19,9 +19,10 @@ import ptBR from 'date-fns/locale/pt-BR';
|
|||
import { splitDateTime } from "../helpers/SplitDateTime";
|
||||
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 { Op } from "sequelize";
|
||||
|
||||
|
||||
|
||||
|
@ -34,6 +35,7 @@ type IndexQuery = {
|
|||
withUnreadMessages: string;
|
||||
queueIds: string;
|
||||
unlimited?: string;
|
||||
searchParamContent?: string
|
||||
};
|
||||
|
||||
interface TicketData {
|
||||
|
@ -41,6 +43,10 @@ interface TicketData {
|
|||
status: string;
|
||||
queueId: number;
|
||||
userId: number;
|
||||
whatsappId?: string | number
|
||||
msg?: string,
|
||||
transfer?: boolean | undefined,
|
||||
fromMe?: boolean
|
||||
}
|
||||
|
||||
|
||||
|
@ -51,6 +57,16 @@ import TicketEmiterSumOpenClosedByUser from "../helpers/OnlineReporEmiterInfoByU
|
|||
import CountTicketService from "../services/TicketServices/CountTicketService";
|
||||
import CountTicketsByUserQueue from "../services/UserServices/CountTicketsByUserQueue";
|
||||
import ShowUserService from "../services/UserServices/ShowUserService";
|
||||
import axios from "axios";
|
||||
import User from "../models/User";
|
||||
import CheckContactOpenTickets from "../helpers/CheckContactOpenTickets";
|
||||
import QueuesByUser from "../services/UserServices/ShowQueuesByUser";
|
||||
import GetDefaultWhatsApp from "../helpers/GetDefaultWhatsApp";
|
||||
import { getWbot } from "../libs/wbot";
|
||||
import endPointQuery from "../helpers/old_EndPointQuery";
|
||||
import Contact from "../models/Contact";
|
||||
import BotIsOnQueue from "../helpers/BotIsOnQueue";
|
||||
import { setMessageAsRead } from "../helpers/SetMessageAsRead";
|
||||
|
||||
export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||
|
||||
|
@ -62,7 +78,8 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
|
|||
showAll,
|
||||
queueIds: queueIdsStringified,
|
||||
withUnreadMessages,
|
||||
unlimited
|
||||
unlimited,
|
||||
searchParamContent
|
||||
} = req.query as IndexQuery;
|
||||
|
||||
|
||||
|
@ -83,32 +100,41 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
|
|||
userId,
|
||||
queueIds,
|
||||
withUnreadMessages,
|
||||
unlimited
|
||||
unlimited,
|
||||
searchParamContent
|
||||
});
|
||||
|
||||
return res.status(200).json({ tickets, count, hasMore });
|
||||
};
|
||||
|
||||
export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||
const { contactId, status, userId }: TicketData = req.body;
|
||||
|
||||
const { contactId, status, userId, msg, queueId }: TicketData = req.body;
|
||||
|
||||
// test del
|
||||
let ticket = await Ticket.findOne({ where: { contactId, status: 'queueChoice' } });
|
||||
const botInfo = await BotIsOnQueue('botqueue')
|
||||
|
||||
let ticket = await Ticket.findOne({
|
||||
where: {
|
||||
[Op.or]: [
|
||||
{ contactId, status: 'queueChoice' },
|
||||
{ contactId, status: 'open', userId: botInfo.userIdBot }
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
if (ticket) {
|
||||
await UpdateTicketService({ ticketData: { status: 'open', userId: userId, }, ticketId: ticket.id });
|
||||
|
||||
await UpdateTicketService({ ticketData: { status: 'open', userId: userId, queueId }, ticketId: ticket.id });
|
||||
|
||||
}
|
||||
else {
|
||||
ticket = await CreateTicketService({ contactId, status, userId });
|
||||
ticket = await CreateTicketService({ contactId, status, userId, queueId });
|
||||
}
|
||||
|
||||
const io = getIO();
|
||||
io.to(ticket.status).emit("ticket", {
|
||||
action: "update",
|
||||
ticket
|
||||
});
|
||||
});
|
||||
//
|
||||
|
||||
|
||||
// const ticket = await CreateTicketService({ contactId, status, userId });
|
||||
|
@ -138,7 +164,6 @@ export const show = async (req: Request, res: Response): Promise<Response> => {
|
|||
return res.status(200).json({ contact, statusChatEnd, schedulesContact });
|
||||
};
|
||||
|
||||
|
||||
export const count = async (req: Request, res: Response): Promise<Response> => {
|
||||
|
||||
// type indexQ = { status: string; date?: string; };
|
||||
|
@ -149,11 +174,11 @@ export const count = async (req: Request, res: Response): Promise<Response> => {
|
|||
return res.status(200).json(ticketCount);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
export const update = async (req: Request, res: Response): Promise<Response> => {
|
||||
|
||||
console.log('ENTROU NO UPDATE TICKET CONTROLLER')
|
||||
|
||||
const { ticketId } = req.params;
|
||||
|
||||
const userOldInfo = await Ticket.findByPk(ticketId)
|
||||
|
@ -175,10 +200,6 @@ export const update = async (req: Request, res: Response): Promise<Response> =>
|
|||
});
|
||||
|
||||
|
||||
///////////////////////////////
|
||||
|
||||
//
|
||||
|
||||
if (scheduleData.farewellMessage) {
|
||||
const whatsapp = await ShowWhatsAppService(ticket.whatsappId);
|
||||
|
||||
|
@ -188,11 +209,11 @@ export const update = async (req: Request, res: Response): Promise<Response> =>
|
|||
await SendWhatsAppMessage({ body: farewellMessage, ticket });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// lembrete // agendamento
|
||||
if (scheduleData.statusChatEndId === '2' || scheduleData.statusChatEndId === '3') {
|
||||
|
||||
|
||||
|
||||
if (isScheduling(scheduleData.schedulingDate, scheduleData.schedulingTime)) {
|
||||
console.log('*** É AGENDAMENTO!')
|
||||
|
@ -217,15 +238,52 @@ export const update = async (req: Request, res: Response): Promise<Response> =>
|
|||
}
|
||||
else {
|
||||
|
||||
const ticketData: TicketData = req.body;
|
||||
// Para aparecer pendente para todos usuarios que estao na fila
|
||||
if (req.body.transfer) {
|
||||
req.body.userId = null
|
||||
}
|
||||
|
||||
let ticketData: TicketData = req.body;
|
||||
|
||||
// console.log('ticketData: ', ticketData)
|
||||
// console.log('ticketData.transfer', ticketData.transfer)
|
||||
|
||||
// return res.send()
|
||||
|
||||
|
||||
// if (ticketData.transfer) {
|
||||
|
||||
// const defaultWhatsapp: any = await GetDefaultWhatsApp(ticketData.userId);
|
||||
|
||||
// const _ticket: any = await Ticket.findByPk(ticketId)
|
||||
|
||||
// if (defaultWhatsapp && ticketData.status != 'open') {
|
||||
|
||||
// await CheckContactOpenTickets(_ticket.dataValues.contactId, defaultWhatsapp.dataValues.id)
|
||||
|
||||
// }
|
||||
|
||||
// ticketData.whatsappId = defaultWhatsapp.dataValues.id
|
||||
|
||||
// }
|
||||
|
||||
console.log('--------> ticketData.status: ', ticketData.status, ' | ticketData.fromMe: ', ticketData.fromMe)
|
||||
|
||||
//ticketData: { status: 'open', userId: 4 } , ticketId
|
||||
|
||||
const { ticket } = await UpdateTicketService({
|
||||
ticketData,
|
||||
ticketId
|
||||
ticketId,
|
||||
});
|
||||
|
||||
|
||||
if (ticketData.status == 'open' && !ticketData.fromMe) {
|
||||
|
||||
await setMessageAsRead(ticket);
|
||||
|
||||
}
|
||||
|
||||
console.log('ticket.unreadMessages: ', ticket.unreadMessages)
|
||||
|
||||
if (ticketData.userId) {
|
||||
|
||||
const dateToday = splitDateTime(new Date(format(new Date(), 'yyyy-MM-dd HH:mm:ss', { locale: ptBR })))
|
||||
|
@ -244,7 +302,7 @@ export const update = async (req: Request, res: Response): Promise<Response> =>
|
|||
|
||||
const dateToday = splitDateTime(new Date(format(new Date(), 'yyyy-MM-dd HH:mm:ss', { locale: ptBR })))
|
||||
|
||||
if (userOldInfo.userId) {
|
||||
if (userOldInfo.userId) {
|
||||
|
||||
TicketEmiterSumOpenClosedByUser(userOldInfo.userId.toString(), dateToday.fullDate, dateToday.fullDate)
|
||||
|
||||
|
@ -258,7 +316,8 @@ export const update = async (req: Request, res: Response): Promise<Response> =>
|
|||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// export const update = async (
|
||||
// req: Request,
|
||||
|
@ -305,3 +364,11 @@ export const remove = async (
|
|||
|
||||
return res.status(200).json({ message: "ticket deleted" });
|
||||
};
|
||||
// export async function setMessageAsRead(ticket: Ticket) {
|
||||
// const wbot_url = await getWbot(ticket.whatsappId);
|
||||
|
||||
// console.log('wbot_url: ', wbot_url, ' | ticket.contact.number: ', ticket.contact.number);
|
||||
|
||||
// await endPointQuery(`${wbot_url}/api/sendSeen`, { number: `${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us` });
|
||||
// }
|
||||
|
||||
|
|
|
@ -14,9 +14,7 @@ export const wbotMonitorRemote = async (req: Request, res: Response): Promise<Re
|
|||
|
||||
const { action, whatsappId, reason } = req.body
|
||||
|
||||
console.log('-----------> ACTION: ', req.body['action'])
|
||||
|
||||
// let whatsapp = await ShowWhatsAppService(whatsappId)
|
||||
console.log('-----------> ACTION: ', req.body['action'])
|
||||
|
||||
const whatsapp: any = await Whatsapp.findByPk(whatsappId, { raw: true })
|
||||
|
||||
|
|
|
@ -3,7 +3,10 @@ const fs = require('fs')
|
|||
import axios from 'axios';
|
||||
import * as https from "https";
|
||||
|
||||
const endPointQuery = async (url: string, method: string, param: string = '') => {
|
||||
const endPointQuery = async (
|
||||
url: string,
|
||||
method: string,
|
||||
params: object) => {
|
||||
|
||||
let response: any = null
|
||||
|
||||
|
@ -26,14 +29,18 @@ const endPointQuery = async (url: string, method: string, param: string = '') =>
|
|||
|
||||
// const url = 'http://177.107.193.124:8095/labs/zabbix-frontend/api/api.php'
|
||||
|
||||
|
||||
response = await axios.post(url, {
|
||||
let payload = {
|
||||
'auth': '0424bd59b807674191e7d77572075f33',
|
||||
'jsonrpc': '2.0',
|
||||
'method': 'chamado.ematendimento',
|
||||
'params[ccusto]': param,
|
||||
// 'method': 'omnihit.consultachamado',
|
||||
id: '101'
|
||||
}, {
|
||||
}
|
||||
|
||||
payload = { ...payload, ...params }
|
||||
|
||||
console.log('xxxxxx payload: ', payload)
|
||||
|
||||
response = await axios.post(url, payload, {
|
||||
httpsAgent,
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
});
|
||||
|
@ -44,6 +51,8 @@ const endPointQuery = async (url: string, method: string, param: string = '') =>
|
|||
console.error(`Erro ao consultar endpoint ${url}: ${error}`);
|
||||
}
|
||||
|
||||
// console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> response: ', response)
|
||||
|
||||
return response
|
||||
|
||||
}
|
||||
|
|
|
@ -6,62 +6,19 @@ import endPointQuery from "./EndpointQuery";
|
|||
import WhatsQueueIndex from "./WhatsQueueIndex";
|
||||
|
||||
|
||||
const hitPortalMonitoring = async (centro_de_custo: string) => {
|
||||
|
||||
let msg_endpoint: any = []
|
||||
|
||||
let response2 = await endPointQuery('http://177.107.193.124:8095/labs/zabbix-frontend/api/api.php', 'post', centro_de_custo.trim())
|
||||
const hitPortalMonitoring = async (params: object) => {
|
||||
|
||||
let response = await endPointQuery('http://177.107.192.247:8095/labs/monitoramentohit/api/api.php', 'post', params)
|
||||
|
||||
if (response2 && response2.data.result) {
|
||||
|
||||
response2 = response2.data.result;
|
||||
|
||||
for (let i = 0; i < response2.length; i++) {
|
||||
|
||||
let data = ''
|
||||
let sub_data = '*Atualizações:*\n\n'
|
||||
|
||||
const properties: any = Object.entries(response2[i]);
|
||||
|
||||
for (let x = 0; x < properties.length; x++) {
|
||||
|
||||
if (typeof (properties[x][1]) != 'object') {
|
||||
|
||||
data += `*${properties[x][0]}*: ${properties[x][1].replace(/(\r\n|\n|\r)/gm, "")}\n`
|
||||
|
||||
}
|
||||
else if (typeof (properties[x][1]) == 'object') {
|
||||
|
||||
const sub_properties = properties[x][1];
|
||||
|
||||
for (let k = 0; k < sub_properties.length; k++) {
|
||||
|
||||
const inner_properties: any = Object.entries(sub_properties[k]);
|
||||
|
||||
for (let y = 0; y < inner_properties.length; y++) {
|
||||
|
||||
sub_data += `*${inner_properties[y][0]}*: ${inner_properties[y][1].replace(/(\r\n|\n|\r)/gm, "")}\n`
|
||||
|
||||
}
|
||||
|
||||
sub_data += '\n'
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
msg_endpoint.push({ header: data, body: sub_data })
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
msg_endpoint = null
|
||||
}
|
||||
|
||||
return msg_endpoint
|
||||
if (response && response.data.result.trim().length > 0) {
|
||||
return response.data.result
|
||||
}
|
||||
else if (response && response.data.result.trim().length === 0) {
|
||||
return ''
|
||||
}
|
||||
else {
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
import { subSeconds } from "date-fns";
|
||||
import Message from "../models/Message";
|
||||
|
||||
import { Op, Sequelize } from "sequelize";
|
||||
|
||||
const mostRepeatedPhrase = async (ticketId: number | string, fromMe: boolean = false) => {
|
||||
|
||||
let res: any = { body: '', occurrences: 0 }
|
||||
|
||||
try {
|
||||
const mostRepeatedPhrase: any = await Message.findOne({
|
||||
where: {
|
||||
ticketId: ticketId,
|
||||
fromMe: fromMe ? fromMe : 0,
|
||||
body: {
|
||||
[Op.notRegexp]: '^[0-9]+$',
|
||||
},
|
||||
updatedAt: {
|
||||
[Op.between]: [+subSeconds(new Date(), 150), +new Date()],
|
||||
},
|
||||
},
|
||||
attributes: [
|
||||
'body',
|
||||
[Sequelize.fn('COUNT', Sequelize.col('body')), 'occurrences'],
|
||||
],
|
||||
|
||||
group: ['body'],
|
||||
order: [[Sequelize.literal('occurrences'), 'DESC']],
|
||||
limit: 1,
|
||||
});
|
||||
|
||||
if (mostRepeatedPhrase) {
|
||||
|
||||
const { body, occurrences } = mostRepeatedPhrase.get();
|
||||
|
||||
console.log(`The most repeated phrase is "${body}" with ${occurrences} occurrences.`);
|
||||
|
||||
const isNumber = /^\d+$/.test(body.trim());
|
||||
|
||||
if (!isNumber) {
|
||||
|
||||
return { body, occurrences }
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
console.log('No phrases found.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('error on MostRepeatedPhrase: ', error)
|
||||
}
|
||||
|
||||
|
||||
|
||||
return { body: '', occurrences: 0 }
|
||||
}
|
||||
|
||||
export default mostRepeatedPhrase;
|
|
@ -10,6 +10,9 @@ import path from "path";
|
|||
import { convertBytes } from "./ConvertBytes";
|
||||
import { deleteScheduleByTicketIdCache } from "./SchedulingNotifyCache";
|
||||
import SchedulingNotify from "../models/SchedulingNotify";
|
||||
import Ticket from "../models/Ticket";
|
||||
import { Sequelize, Op } from "sequelize";
|
||||
|
||||
|
||||
const fastFolderSize = require('fast-folder-size')
|
||||
const { promisify } = require('util')
|
||||
|
@ -41,33 +44,39 @@ const monitor = async () => {
|
|||
try {
|
||||
|
||||
const { schedulingNotifies, count, hasMore } = await ListSchedulingNotifyService({ searchParam: dateParm, pageNumber: "1" });
|
||||
|
||||
if (schedulingNotifies && schedulingNotifies.length > 0) {
|
||||
|
||||
for (let i = 0; i < schedulingNotifies.length; i++) {
|
||||
if (schedulingNotifies && schedulingNotifies.length > 0) {
|
||||
|
||||
for (let i = 0; i < schedulingNotifies.length; i++) {
|
||||
|
||||
const ticket: any = await ShowTicketService(+schedulingNotifies[i].ticketId);
|
||||
|
||||
let _ticket = await Ticket.findOne({
|
||||
where: {
|
||||
contactId: ticket.contactId,
|
||||
status: { [Op.in]: ['open', 'pending'] }
|
||||
}
|
||||
})
|
||||
|
||||
await deleteScheduleByTicketIdCache(schedulingNotifies[i].ticketId)
|
||||
|
||||
await DeleteSchedulingNotifyService(schedulingNotifies[i].id)
|
||||
|
||||
if (_ticket) continue
|
||||
|
||||
if (ticket.dataValues.status == 'closed') {
|
||||
await ticket.update({ status: 'pending' })
|
||||
}
|
||||
|
||||
const ticket = await ShowTicketService(+schedulingNotifies[i].ticketId);
|
||||
|
||||
await new Promise(f => setTimeout(f, 3000));
|
||||
|
||||
if(!ticket.queue){
|
||||
await ticket.update({status: 'open'})
|
||||
}
|
||||
|
||||
// SetTicketMessagesAsRead(ticket);
|
||||
|
||||
await SendWhatsAppMessage({
|
||||
body: schedulingNotifies[i].message, ticket
|
||||
});
|
||||
|
||||
await deleteScheduleByTicketIdCache(schedulingNotifies[i].ticketId)
|
||||
|
||||
await DeleteSchedulingNotifyService(schedulingNotifies[i].id)
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -173,7 +182,7 @@ _fifo = setInterval(SchedulingNotifySendMessage, 5000);
|
|||
|
||||
module.exports = SchedulingNotifySendMessage
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -14,19 +14,7 @@ function sendWhatsAppMessageSocket(ticket: Ticket, body: string, quotedMsgSerial
|
|||
quotedMessageId: quotedMsgSerializedId,
|
||||
linkPreview: false
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// io.emit("send_message", {
|
||||
// action: "create",
|
||||
// msg: {
|
||||
// number: `${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us`,
|
||||
// body: body,
|
||||
// quotedMessageId: quotedMsgSerializedId,
|
||||
// linkPreview: false
|
||||
// }
|
||||
// });
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
import { getWbot } from "../libs/wbot";
|
||||
import Ticket from "../models/Ticket";
|
||||
import endPointQuery from "./old_EndPointQuery";
|
||||
|
||||
export async function setMessageAsRead(ticket: Ticket) {
|
||||
|
||||
const wbot_url = await getWbot(ticket.whatsappId);
|
||||
|
||||
console.log('from wbotMessagelistener wbot_url: ', wbot_url, ' | ticket.contact.number: ', ticket.contact.number);
|
||||
|
||||
await endPointQuery(`${wbot_url}/api/sendSeen`, { number: `${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us` });
|
||||
}
|
|
@ -45,13 +45,7 @@ export const initIO = (httpServer: Server): SocketIO => {
|
|||
|
||||
|
||||
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}`);
|
||||
|
@ -65,6 +59,8 @@ export const initIO = (httpServer: Server): SocketIO => {
|
|||
|
||||
socket.on("message_create", async (data: any) => {
|
||||
|
||||
// console.log('data: ', data)
|
||||
|
||||
handleMessage(data.msg, data);
|
||||
|
||||
});
|
||||
|
|
|
@ -4,6 +4,6 @@ import * as HitController from "../controllers/HitController";
|
|||
|
||||
const hitRoutes = express.Router();
|
||||
|
||||
hitRoutes.post("/espacolaser/incidente", HitController.hit);
|
||||
hitRoutes.post("/omnihit/incidente", HitController.hit);
|
||||
|
||||
export default hitRoutes;
|
||||
|
|
|
@ -13,6 +13,8 @@ messageRoutes.get("/messages/:ticketId", isAuth, MessageController.index);
|
|||
|
||||
messageRoutes.post("/messages/:ticketId", isAuth, upload.array("medias"), MessageController.store);
|
||||
|
||||
// messageRoutes.put("/messages/:ticketId", isAuth, MessageController.update)
|
||||
|
||||
messageRoutes.delete("/messages/:messageId", isAuth, MessageController.remove);
|
||||
|
||||
export default messageRoutes;
|
||||
export default messageRoutes;
|
|
@ -21,18 +21,23 @@ let flatten = require('flat')
|
|||
interface Request {
|
||||
contactId: number;
|
||||
status: string;
|
||||
userId: number;
|
||||
userId: number;
|
||||
queueId?: number | undefined;
|
||||
}
|
||||
|
||||
const CreateTicketService = async ({
|
||||
contactId,
|
||||
status,
|
||||
userId
|
||||
userId,
|
||||
queueId = undefined
|
||||
}: Request): Promise<Ticket> => {
|
||||
|
||||
|
||||
console.log('========> queueId: ', queueId)
|
||||
|
||||
try {
|
||||
|
||||
const defaultWhatsapp = await GetDefaultWhatsApp(userId);
|
||||
const defaultWhatsapp = await GetDefaultWhatsApp(userId);
|
||||
|
||||
await CheckContactOpenTickets(contactId);
|
||||
|
||||
|
@ -42,7 +47,8 @@ const CreateTicketService = async ({
|
|||
contactId,
|
||||
status,
|
||||
isGroup,
|
||||
userId
|
||||
userId,
|
||||
queueId
|
||||
});
|
||||
|
||||
const ticket = await Ticket.findByPk(id, { include: ["contact"] });
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
import { subHours, subMinutes, subSeconds } from "date-fns";
|
||||
import { Op } from "sequelize";
|
||||
import BotIsOnQueue from "../../helpers/BotIsOnQueue";
|
||||
import Contact from "../../models/Contact";
|
||||
import Ticket from "../../models/Ticket";
|
||||
import ShowWhatsAppService from "../WhatsappService/ShowWhatsAppService";
|
||||
import ShowTicketService from "./ShowTicketService";
|
||||
import AppError from "../../errors/AppError";
|
||||
import { userInfo } from "os";
|
||||
import { sendDialogflowAwswer } from "../WbotServices/wbotMessageListener";
|
||||
import ShowQueueService from "../QueueService/ShowQueueService";
|
||||
import UpdateTicketService from "./UpdateTicketService";
|
||||
|
||||
|
||||
const FindOrCreateTicketServiceBot = async (
|
||||
contact: Contact,
|
||||
whatsappId: number,
|
||||
unreadMessages: number,
|
||||
groupContact?: Contact
|
||||
): Promise<any> => {
|
||||
|
||||
try {
|
||||
|
||||
let ticket = await Ticket.findOne({
|
||||
where: {
|
||||
status: {
|
||||
[Op.or]: ["open", "pending", "queueChoice"]
|
||||
},
|
||||
contactId: groupContact ? groupContact.id : contact.id
|
||||
}
|
||||
});
|
||||
|
||||
const { queues, greetingMessage } = await ShowWhatsAppService(whatsappId);
|
||||
|
||||
|
||||
//Habilitar esse caso queira usar o bot
|
||||
const botInfo = await BotIsOnQueue('botqueue')
|
||||
// const botInfo = { isOnQueue: false }
|
||||
|
||||
|
||||
|
||||
if (ticket) {
|
||||
await ticket.update({ unreadMessages });
|
||||
}
|
||||
|
||||
// if (!ticket && groupContact) {
|
||||
// ticket = await Ticket.findOne({
|
||||
// where: {
|
||||
// contactId: groupContact.id
|
||||
// },
|
||||
// order: [["updatedAt", "DESC"]]
|
||||
// });
|
||||
|
||||
|
||||
|
||||
// if (ticket) {
|
||||
|
||||
// await ticket.update({
|
||||
// status: "pending",
|
||||
// userId: null,
|
||||
// unreadMessages
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
|
||||
if (!ticket && !groupContact) {
|
||||
|
||||
console.log('BOT CREATING OR REOPENING THE TICKET')
|
||||
|
||||
ticket = await Ticket.findOne({
|
||||
where: {
|
||||
contactId: contact.id,
|
||||
userId: botInfo.userIdBot
|
||||
},
|
||||
order: [["updatedAt", "DESC"]]
|
||||
});
|
||||
|
||||
if (ticket) {
|
||||
|
||||
await ticket.update({
|
||||
status: "open",
|
||||
userId: botInfo.userIdBot,
|
||||
unreadMessages
|
||||
});
|
||||
|
||||
console.log('lxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')
|
||||
|
||||
await dialogFlowStartContext(contact, ticket, botInfo);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
let created = false
|
||||
|
||||
if (!ticket) {
|
||||
|
||||
created = true
|
||||
|
||||
let status = "open"
|
||||
|
||||
if (queues.length > 1 && !botInfo.isOnQueue) {
|
||||
status = "queueChoice"
|
||||
}
|
||||
|
||||
ticket = await Ticket.create({
|
||||
contactId: groupContact ? groupContact.id : contact.id,
|
||||
status: status,
|
||||
userId: botInfo.userIdBot,
|
||||
isGroup: !!groupContact,
|
||||
unreadMessages,
|
||||
whatsappId
|
||||
});
|
||||
|
||||
console.log('yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy')
|
||||
|
||||
await dialogFlowStartContext(contact, ticket, botInfo);
|
||||
|
||||
}
|
||||
|
||||
ticket = await ShowTicketService(ticket.id);
|
||||
|
||||
return { ticket, created };
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('===> Error on FindOrCreateTicketServiceBot.ts file: \n', error)
|
||||
throw new AppError(error.message);
|
||||
}
|
||||
};
|
||||
|
||||
export default FindOrCreateTicketServiceBot;
|
||||
|
||||
async function dialogFlowStartContext(contact: Contact, ticket: Ticket, botInfo: any) {
|
||||
|
||||
let msg: any = { type: 'chat', from: `${contact.number}@c.us`, body: '0' };
|
||||
|
||||
let queue = await ShowQueueService(botInfo.botQueueId);
|
||||
|
||||
await UpdateTicketService({
|
||||
ticketData: { queueId: queue.id },
|
||||
ticketId: ticket.id
|
||||
});
|
||||
|
||||
ticket = await ShowTicketService(ticket.id);
|
||||
|
||||
await sendDialogflowAwswer(ticket.whatsappId, ticket, msg, contact, false);
|
||||
}
|
||||
|
|
@ -15,8 +15,11 @@ const dateToday = splitDateTime(new Date(format(new Date(), 'yyyy-MM-dd HH:mm:ss
|
|||
|
||||
import ListTicketServiceCache from "./ListTicketServiceCache"
|
||||
|
||||
import { searchTicketCache, loadTicketsCache } from '../../helpers/TicketCache'
|
||||
import { searchTicketCache, loadTicketsCache } from '../../helpers/TicketCache'
|
||||
import { getWbot } from "../../libs/wbot";
|
||||
import User from "../../models/User";
|
||||
|
||||
|
||||
|
||||
|
||||
interface Request {
|
||||
|
@ -29,6 +32,7 @@ interface Request {
|
|||
withUnreadMessages?: string;
|
||||
queueIds: number[];
|
||||
unlimited?: string;
|
||||
searchParamContent?: string;
|
||||
}
|
||||
|
||||
interface Response {
|
||||
|
@ -47,9 +51,12 @@ const ListTicketsService = async ({
|
|||
showAll,
|
||||
userId,
|
||||
withUnreadMessages,
|
||||
unlimited = 'false'
|
||||
unlimited = 'false',
|
||||
searchParamContent = ""
|
||||
}: Request): Promise<Response> => {
|
||||
|
||||
console.log('----------> searchParamContent: ', searchParamContent)
|
||||
|
||||
let whereCondition: Filterable["where"] = { [Op.or]: [{ userId }, { status: "pending" }], queueId: { [Op.or]: [queueIds, null] } };
|
||||
|
||||
console.log('PAGE NUMBER TICKET: ', pageNumber)
|
||||
|
@ -64,9 +71,6 @@ const ListTicketsService = async ({
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (searchParam && searchParam.trim().length > 0 && process.env.CACHE) {
|
||||
|
||||
try {
|
||||
|
@ -147,20 +151,33 @@ const ListTicketsService = async ({
|
|||
|
||||
if (searchParam) {
|
||||
const sanitizedSearchParam = searchParam.toLocaleLowerCase().trim();
|
||||
const sanitizedSearchParamContent = searchParamContent.toLocaleLowerCase().trim();
|
||||
|
||||
|
||||
if (searchParamContent.length > 0) {
|
||||
|
||||
includeCondition = [
|
||||
...includeCondition,
|
||||
{
|
||||
model: Message,
|
||||
as: "messages",
|
||||
attributes: ["id", "body"],
|
||||
where: {
|
||||
body: where(fn("LOWER", col("body")), "LIKE", `%${sanitizedSearchParamContent}%`)
|
||||
},
|
||||
required: false,
|
||||
duplicating: false
|
||||
}
|
||||
];
|
||||
|
||||
whereCondition = {
|
||||
...whereCondition,
|
||||
"$message.body$": where(fn("LOWER", col("body")), "LIKE", `%${sanitizedSearchParamContent}%`)
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
// includeCondition = [
|
||||
// ...includeCondition,
|
||||
// {
|
||||
// model: Message,
|
||||
// as: "messages",
|
||||
// attributes: ["id", "body"],
|
||||
// where: {
|
||||
// body: where(fn("LOWER", col("body")), "LIKE", `%${sanitizedSearchParam}%`)
|
||||
// },
|
||||
// required: false,
|
||||
// duplicating: false
|
||||
// }
|
||||
// ];
|
||||
|
||||
whereCondition = {
|
||||
...whereCondition,
|
||||
|
@ -171,11 +188,17 @@ const ListTicketsService = async ({
|
|||
|
||||
{ "$contact.number$": { [Op.like]: `%${sanitizedSearchParam}%` } },
|
||||
|
||||
// {
|
||||
// "$message.body$": where(fn("LOWER", col("body")), "LIKE", `%${sanitizedSearchParam}%`)
|
||||
// }
|
||||
]
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
const userProfile: any = await User.findByPk(userId)
|
||||
|
||||
if (userProfile.dataValues.profile != 'admin' && userProfile.dataValues.profile != 'master') {
|
||||
whereCondition = { ...whereCondition, userId }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (date) {
|
||||
|
@ -201,8 +224,6 @@ const ListTicketsService = async ({
|
|||
const offset = limit * (+pageNumber - 1);
|
||||
|
||||
|
||||
|
||||
|
||||
const { count, rows: tickets } = await Ticket.findAndCountAll({
|
||||
where: whereCondition,
|
||||
include: includeCondition,
|
||||
|
|
|
@ -9,53 +9,82 @@ import { userInfo } from "os";
|
|||
|
||||
import { Op, where } from "sequelize";
|
||||
|
||||
import { Sequelize } from "sequelize";
|
||||
import moment from 'moment';
|
||||
|
||||
import { startOfDay, endOfDay, parseISO, getDate} from "date-fns";
|
||||
import { Sequelize } from "sequelize";
|
||||
import moment from 'moment';
|
||||
|
||||
import { startOfDay, endOfDay, parseISO, getDate, subSeconds } from "date-fns";
|
||||
import { string } from "yup/lib/locale";
|
||||
|
||||
|
||||
function paramsQuery(params: string[]) {
|
||||
|
||||
let like = []
|
||||
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
like.push({ [Op.like]: `%${params[i]}%` })
|
||||
}
|
||||
return like
|
||||
}
|
||||
|
||||
//Report by user, startDate, endDate
|
||||
const ShowTicketMessage = async (ticketId: string | number, onlyNumber: boolean = false, fromMe?:boolean, limit?: number, regexp?: string): Promise<Message[]> => {
|
||||
|
||||
const ShowTicketMessage = async (
|
||||
ticketId: string | number,
|
||||
limit: number,
|
||||
fromMe: boolean,
|
||||
params?: string[],
|
||||
onlyNumber?: boolean,
|
||||
regexp?: string): Promise<Message[]> => {
|
||||
|
||||
let where_clause = {}
|
||||
|
||||
if(onlyNumber){
|
||||
where_clause = {
|
||||
ticketId: ticketId,
|
||||
fromMe: fromMe ? fromMe : 0,
|
||||
//body: {[Op.regexp]: '^[0-9]*$'},
|
||||
// body: {[Op.regexp]: '^[0-3]$'},
|
||||
body: {[Op.regexp]: regexp},
|
||||
}
|
||||
if (onlyNumber) {
|
||||
where_clause = {
|
||||
ticketId: ticketId,
|
||||
fromMe: fromMe ? fromMe : 0,
|
||||
body: { [Op.regexp]: regexp },
|
||||
}
|
||||
}
|
||||
else{
|
||||
where_clause = {
|
||||
ticketId: ticketId,
|
||||
fromMe: fromMe ? fromMe : 0,
|
||||
}
|
||||
else if (params && params.length > 0) {
|
||||
where_clause = {
|
||||
ticketId: ticketId,
|
||||
fromMe: fromMe ? fromMe : 0,
|
||||
updatedAt: {
|
||||
[Op.between]: [+subSeconds(new Date(), 50), +new Date()],
|
||||
},
|
||||
body: {
|
||||
[Op.or]: paramsQuery(params)
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
where_clause = {
|
||||
ticketId: ticketId,
|
||||
fromMe: fromMe ? fromMe : 0,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
const ticket = await Message.findAll({
|
||||
|
||||
where: where_clause ,
|
||||
limit: limit ? limit : 10000,
|
||||
raw:true,
|
||||
attributes: ['body', 'read', 'mediaType','fromMe', 'mediaUrl', [Sequelize.fn("DATE_FORMAT",Sequelize.col("createdAt"),"%d/%m/%Y %H:%i:%s"),"createdAt"]],
|
||||
const ticket = await Message.findAll({
|
||||
|
||||
where: where_clause,
|
||||
limit: limit,
|
||||
raw: true,
|
||||
attributes: ['body', 'read', 'mediaType', 'fromMe', 'mediaUrl', [Sequelize.fn("DATE_FORMAT", Sequelize.col("createdAt"), "%d/%m/%Y %H:%i:%s"), "createdAt"]],
|
||||
|
||||
order: [
|
||||
['createdAt', 'DESC']
|
||||
]
|
||||
|
||||
});
|
||||
|
||||
|
||||
]
|
||||
|
||||
});
|
||||
|
||||
|
||||
if (!ticket) {
|
||||
throw new AppError("ERR_NO_TICKET_FOUND", 404);
|
||||
}
|
||||
|
||||
return ticket;
|
||||
};
|
||||
};
|
||||
|
||||
export default ShowTicketMessage;
|
||||
|
|
|
@ -27,7 +27,7 @@ const ShowTicketService = async (id: string | number): Promise<Ticket> => {
|
|||
]
|
||||
});
|
||||
|
||||
console.log('>>>>>>>>>>>>>>>>>>>>>>>> ShowTicketService: ',ticket?.whatsappId)
|
||||
// console.log('>>>>>>>>>>>>>>>>>>>>>>>> ShowTicketService: ',ticket?.whatsappId)
|
||||
|
||||
if (!ticket) {
|
||||
throw new AppError("ERR_NO_TICKET_FOUND", 404);
|
||||
|
|
|
@ -8,20 +8,23 @@ import ShowTicketService from "./ShowTicketService";
|
|||
|
||||
import { createOrUpdateTicketCache } from '../../helpers/TicketCache'
|
||||
import AppError from "../../errors/AppError";
|
||||
import sendWhatsAppMessageSocket from "../../helpers/SendWhatsappMessageSocket";
|
||||
var flatten = require('flat')
|
||||
|
||||
|
||||
|
||||
|
||||
interface TicketData {
|
||||
status?: string;
|
||||
userId?: number;
|
||||
queueId?: number;
|
||||
statusChatEnd?: string
|
||||
statusChatEnd?: string;
|
||||
unreadMessages?: number;
|
||||
}
|
||||
|
||||
interface Request {
|
||||
ticketData: TicketData;
|
||||
ticketId: string | number;
|
||||
ticketId: string | number;
|
||||
msg?: string
|
||||
}
|
||||
|
||||
interface Response {
|
||||
|
@ -32,83 +35,94 @@ interface Response {
|
|||
|
||||
const UpdateTicketService = async ({
|
||||
ticketData,
|
||||
ticketId
|
||||
ticketId,
|
||||
msg=''
|
||||
}: Request): Promise<Response> => {
|
||||
|
||||
try {
|
||||
|
||||
const { status, userId, queueId, statusChatEnd } = ticketData;
|
||||
const { status, userId, queueId, statusChatEnd, unreadMessages } = ticketData;
|
||||
|
||||
const ticket = await ShowTicketService(ticketId);
|
||||
// await SetTicketMessagesAsRead(ticket);
|
||||
const ticket = await ShowTicketService(ticketId);
|
||||
// await SetTicketMessagesAsRead(ticket);
|
||||
|
||||
const oldStatus = ticket.status;
|
||||
const oldUserId = ticket.user?.id;
|
||||
const oldStatus = ticket.status;
|
||||
const oldUserId = ticket.user?.id;
|
||||
|
||||
if (oldStatus === "closed") {
|
||||
await CheckContactOpenTickets(ticket.contact.id);
|
||||
}
|
||||
|
||||
await ticket.update({
|
||||
status,
|
||||
queueId,
|
||||
userId,
|
||||
statusChatEnd
|
||||
});
|
||||
if (oldStatus === "closed") {
|
||||
await CheckContactOpenTickets(ticket.contact.id);
|
||||
}
|
||||
|
||||
await ticket.reload();
|
||||
|
||||
// TEST DEL
|
||||
try {
|
||||
|
||||
// const { name, number } = await ShowContactService(ticket.contactId)
|
||||
|
||||
let jsonString = JSON.stringify(ticket); //convert to string to remove the sequelize specific meta data
|
||||
let ticket_obj = JSON.parse(jsonString); //to make plain json
|
||||
delete ticket_obj['contact']['extraInfo']
|
||||
delete ticket_obj['user']
|
||||
|
||||
ticket_obj = flatten(ticket_obj)
|
||||
|
||||
await createOrUpdateTicketCache(`ticket:${ticket.id}`, ticket_obj)
|
||||
|
||||
} catch (error) {
|
||||
console.log('There was an error on UpdateTicketService.ts on createTicketCache: ', error)
|
||||
}
|
||||
//
|
||||
|
||||
let io = getIO();
|
||||
|
||||
if (ticket.status !== oldStatus || ticket.user?.id !== oldUserId) {
|
||||
io.to(oldStatus).emit("ticket", {
|
||||
action: "delete",
|
||||
ticketId: ticket.id
|
||||
await ticket.update({
|
||||
status,
|
||||
queueId,
|
||||
userId,
|
||||
unreadMessages,
|
||||
statusChatEnd
|
||||
});
|
||||
}
|
||||
|
||||
await ticket.reload();
|
||||
|
||||
if (msg.length > 0) {
|
||||
|
||||
setTimeout(async () => {
|
||||
|
||||
sendWhatsAppMessageSocket(ticket, msg)
|
||||
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
// TEST DEL
|
||||
try {
|
||||
|
||||
// const { name, number } = await ShowContactService(ticket.contactId)
|
||||
|
||||
let jsonString = JSON.stringify(ticket); //convert to string to remove the sequelize specific meta data
|
||||
let ticket_obj = JSON.parse(jsonString); //to make plain json
|
||||
delete ticket_obj['contact']['extraInfo']
|
||||
delete ticket_obj['user']
|
||||
|
||||
ticket_obj = flatten(ticket_obj)
|
||||
|
||||
await createOrUpdateTicketCache(`ticket:${ticket.id}`, ticket_obj)
|
||||
|
||||
} catch (error) {
|
||||
console.log('There was an error on UpdateTicketService.ts on createTicketCache: ', error)
|
||||
}
|
||||
//
|
||||
|
||||
let io = getIO();
|
||||
|
||||
if (ticket.status !== oldStatus || ticket.user?.id !== oldUserId) {
|
||||
io.to(oldStatus).emit("ticket", {
|
||||
action: "delete",
|
||||
ticketId: ticket.id
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
io.to(ticket.status)
|
||||
.to("notification")
|
||||
.to(ticketId.toString())
|
||||
.emit("ticket", {
|
||||
io.to(ticket.status)
|
||||
.to("notification")
|
||||
.to(ticketId.toString())
|
||||
.emit("ticket", {
|
||||
action: "update",
|
||||
ticket
|
||||
});
|
||||
|
||||
|
||||
io.emit("ticketStatus", {
|
||||
action: "update",
|
||||
ticket
|
||||
ticketStatus: { ticketId: ticket.id, status: ticket.status }
|
||||
});
|
||||
|
||||
|
||||
io.emit("ticketStatus", {
|
||||
action: "update",
|
||||
ticketStatus: { ticketId: ticket.id, status: ticket.status }
|
||||
});
|
||||
return { ticket, oldStatus, oldUserId };
|
||||
|
||||
|
||||
return { ticket, oldStatus, oldUserId };
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('===> Error on UpdateTicketService.ts file: \n', error)
|
||||
throw new AppError(error.message);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
export default UpdateTicketService;
|
||||
export default UpdateTicketService;
|
|
@ -45,10 +45,11 @@ const SendWhatsAppMessage = async ({
|
|||
|
||||
try {
|
||||
|
||||
let timestamp = Math.floor(Date.now() / 1000)
|
||||
// let timestamp = Math.floor(Date.now() / 1000)
|
||||
let timestamp = Date.now() + String(Math.floor(Math.random() * 1000))
|
||||
var timetaken = `########################################${timestamp}| TicketId: ${ticket.id} => Time taken to send the message`;
|
||||
|
||||
console.time(timetaken)
|
||||
console.time(timetaken)
|
||||
|
||||
|
||||
let quotedMsgSerializedId: string | undefined;
|
||||
|
@ -67,9 +68,15 @@ const SendWhatsAppMessage = async ({
|
|||
|
||||
let listWhatsapp = null
|
||||
|
||||
// listWhatsapp = await searchWhatsappCache(`${ticket.whatsappId}`, 'CONNECTED')
|
||||
// listWhatsapp = await searchWhatsappCache(`${ticket.whatsappId}`, 'CONNECTED')
|
||||
|
||||
console.log('ticket.whatsappIdticket.whatsappIdticket.whatsappIdticket: ', ticket.whatsappId)
|
||||
if (!ticket.whatsappId) {
|
||||
|
||||
const defaultWhatsapp: any = await GetDefaultWhatsApp(ticket.userId);
|
||||
|
||||
await ticket.update({ whatsappId: +defaultWhatsapp.id });
|
||||
|
||||
}
|
||||
|
||||
if (!listWhatsapp) {
|
||||
listWhatsapp = await ListWhatsAppsNumber(ticket.whatsappId, 'CONNECTED')
|
||||
|
@ -77,12 +84,8 @@ const SendWhatsAppMessage = async ({
|
|||
|
||||
if (listWhatsapp.whatsapp && listWhatsapp.whatsapp.status != 'CONNECTED' && listWhatsapp.whatsapps.length > 0) {
|
||||
|
||||
// console.log('kkkkkkkkkkkkkkkkkkkkkkkkkkkk: ', listWhatsapp.whatsapps[0].id)
|
||||
|
||||
await ticket.update({ whatsappId: + listWhatsapp.whatsapps[0].id });
|
||||
|
||||
let _ticket = await Ticket.findByPk(listWhatsapp.whatsapps[0].id)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -123,9 +126,9 @@ const SendWhatsAppMessage = async ({
|
|||
|
||||
try {
|
||||
|
||||
sendWhatsAppMessageSocket(ticket, body, quotedMsgSerializedId, number);
|
||||
sendWhatsAppMessageSocket(ticket, body, quotedMsgSerializedId, number);
|
||||
|
||||
await ticket.update({ lastMessage: body });
|
||||
await ticket.update({ lastMessage: body });
|
||||
|
||||
await updateTicketCacheByTicketId(ticket.id, { lastMessage: body, updatedAt: new Date(ticket.updatedAt).toISOString() })
|
||||
|
||||
|
|
|
@ -71,6 +71,10 @@ import sendWhatsAppMessageSocket from "../../helpers/SendWhatsappMessageSocket";
|
|||
import { getWhatsappIds, setWhatsappId } from "../../helpers/WhatsappIdMultiSessionControl";
|
||||
import SendWhatsAppMedia from "./SendWhatsAppMedia";
|
||||
import AppError from "../../errors/AppError";
|
||||
import { tr } from "date-fns/locale";
|
||||
import mostRepeatedPhrase from "../../helpers/MostRepeatedPhrase";
|
||||
import FindOrCreateTicketServiceBot from "../TicketServices/FindOrCreateTicketServiceBot";
|
||||
import { setMessageAsRead } from "../../helpers/SetMessageAsRead";
|
||||
|
||||
|
||||
|
||||
|
@ -223,23 +227,44 @@ const queryEndPointHit = async (centro_de_custo: string) => {
|
|||
|
||||
let msg_endpoint: any = []
|
||||
|
||||
let response2 = await endPointQuery('http://177.107.193.124:8095/labs/zabbix-frontend/api/api.php', 'post', centro_de_custo.trim())
|
||||
let response2 = await endPointQuery('http://177.107.193.124:8095/labs/zabbix-frontend/api/api.php', 'post', { 'params[cod_web]': centro_de_custo.trim(), })
|
||||
|
||||
if (response2 && response2.data.result) {
|
||||
|
||||
response2 = response2.data.result;
|
||||
|
||||
|
||||
for (let i = 0; i < response2.length; i++) {
|
||||
|
||||
let data = ''
|
||||
let sub_data = '*Atualizações:*\n\n'
|
||||
|
||||
const properties: any = Object.entries(response2[i]);
|
||||
let properties: any = Object.entries(response2[i]);
|
||||
|
||||
for (let x = 0; x < properties.length; x++) {
|
||||
|
||||
if (typeof (properties[x][1]) != 'object') {
|
||||
|
||||
if (properties[x][0] === 'n_chamado_web') {
|
||||
properties[x][0] = 'Protocolo'
|
||||
}
|
||||
else if (properties[x][0] === 'nome_cliente') {
|
||||
properties[x][0] = 'Nome do cliente'
|
||||
}
|
||||
else if (properties[x][0] === 'quando_inicio') {
|
||||
properties[x][0] = 'Data de abertura'
|
||||
}
|
||||
else if (properties[x][0] === 'nome_filial') {
|
||||
properties[x][0] = 'Nome da filial'
|
||||
}
|
||||
else if (properties[x][0] === 'cod_web') {
|
||||
properties[x][0] = 'Codigo do cliente'
|
||||
}
|
||||
else if (properties[x][0] === 'id' || properties[x][0] === 'cliente_id') {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
data += `*${properties[x][0]}*: ${properties[x][1].replace(/(\r\n|\n|\r)/gm, "")}\n`
|
||||
|
||||
}
|
||||
|
@ -249,10 +274,20 @@ const queryEndPointHit = async (centro_de_custo: string) => {
|
|||
|
||||
for (let k = 0; k < sub_properties.length; k++) {
|
||||
|
||||
const inner_properties: any = Object.entries(sub_properties[k]);
|
||||
let inner_properties: any = Object.entries(sub_properties[k]);
|
||||
|
||||
for (let y = 0; y < inner_properties.length; y++) {
|
||||
|
||||
if (inner_properties[y][0] === 'texto') {
|
||||
inner_properties[y][0] = 'Informação'
|
||||
}
|
||||
else if (inner_properties[y][0] === 'quando') {
|
||||
inner_properties[y][0] = 'Data da Informação'
|
||||
}
|
||||
else if (inner_properties[y][0] === 'login') {
|
||||
continue
|
||||
}
|
||||
|
||||
sub_data += `*${inner_properties[y][0]}*: ${inner_properties[y][1].replace(/(\r\n|\n|\r)/gm, "")}\n`
|
||||
|
||||
}
|
||||
|
@ -324,7 +359,7 @@ const monitoramento_response2 = async (response: any | null, wbot: any, contact:
|
|||
|
||||
|
||||
|
||||
async function sendDelayedMessages(wbot: Session, ticket: Ticket, contact: Contact, message: string, _msg?: WbotMessage) {
|
||||
async function sendDelayedMessages(wbot: any, ticket: Ticket, contact: Contact, message: string, _msg?: WbotMessage) {
|
||||
const body = message.replace(/\\n/g, '\n');
|
||||
|
||||
if (body.search('dialog_actions') != -1) {
|
||||
|
@ -335,204 +370,132 @@ async function sendDelayedMessages(wbot: Session, ticket: Ticket, contact: Conta
|
|||
|
||||
if (msgAction.actions[0] == 'request_endpoint') {
|
||||
|
||||
// OLD
|
||||
// const sentMessage = await wbot.sendMessage(`${contact.number}@c.us`, msgAction.msgBody);
|
||||
// await verifyMessage(sentMessage, ticket, contact);
|
||||
// await new Promise(f => setTimeout(f, 1000));
|
||||
|
||||
// NEW
|
||||
await SendWhatsAppMessage({ body: msgAction.msgBody, ticket, number: `${contact.number}@c.us` })
|
||||
|
||||
// const url = 'http://177.107.193.124:8095/labs/zabbix-frontend/api/api.php/99383'
|
||||
|
||||
// const url = 'https://sos.espacolaser.com.br/api/whatsapps/ticket/R32656'
|
||||
let endPointResponse = await endPointQuery(msgAction.actions[1], 'get')
|
||||
let aux = msgAction.actions[1].split('/')
|
||||
|
||||
console.log('Object.entries(endPointResponse.data).length: ', Object.entries(endPointResponse.data).length)
|
||||
// console.log('endPointResonse.status: ',typeof(endPointResponse.status))
|
||||
let cod_web
|
||||
|
||||
if (endPointResponse && endPointResponse.status == 200 && Object.entries(endPointResponse.data).length > 0) {
|
||||
if (aux && aux.length > 0) {
|
||||
cod_web = aux[aux.length - 1]
|
||||
}
|
||||
|
||||
// endPointResponse.data.categoria = 'ELOS'
|
||||
// endPointResponse.data.categoria = 'INFRAESTRUTURA'
|
||||
// endPointResponse.data.subcategoria = 'INTERNET'
|
||||
// endPointResponse.data.terceiro_nivel = 'QUEDA TOTAL'
|
||||
let params = msgAction.actions[1].split('api.php')[1].slice(1).split('/')
|
||||
|
||||
console.log('-------------> endPointResponse.data.categoria: ', endPointResponse.data.categoria)
|
||||
let url = msgAction.actions[1].replace(/\.php.*/, '.php')
|
||||
|
||||
if (endPointResponse.data.categoria != 'INFRAESTRUTURA' && endPointResponse.data.categoria != 'ELOS') {
|
||||
botSendMessage(ticket, contact, wbot, `A categorização desse chamado não se enquadra no atendimento deste canal!\n\n _Digite *0* para voltar ao menu principal._`)
|
||||
return
|
||||
}
|
||||
let response: any = ''
|
||||
|
||||
const response = Object.entries(endPointResponse.data);
|
||||
let msg_endpoint_response = ''
|
||||
let msg_endpoint2: any = []
|
||||
let centro_de_custo = ''
|
||||
if (params[0] === 'validate_n_chamado_web') {
|
||||
|
||||
let valid = await endPointQuery(
|
||||
'http://177.107.192.247:8095/labs/monitoramentohit/api/api.php',
|
||||
'post',
|
||||
{
|
||||
'params[n_chamado_web]': params[1],
|
||||
'method': 'omnihit.consultachamadostatus'
|
||||
})
|
||||
|
||||
|
||||
for (let i = 0; i < response.length; i++) {
|
||||
if (valid && valid.data.result == 'open') {
|
||||
|
||||
if (['id_solicitante', 'centro_custo_departamento', 'departamento_do_formulario', 'centro_de_custo_do_departamento_do_formulario'].includes(response[i][0]))
|
||||
continue
|
||||
|
||||
msg_endpoint_response += `*${response[i][0]}*: ${String(response[i][1]).replace(/(<([^>]+)>)/gi, "")}\n`
|
||||
botSendMessage(ticket, `Protocolo validado, por favor, pode digitar o texto a ser adicionado no histórico do protocolo *${params[1]}*`)
|
||||
|
||||
}
|
||||
else if (valid && valid.data.result == 'notfound') {
|
||||
|
||||
|
||||
|
||||
if (endPointResponse.data.centro_custo_departamento && endPointResponse.data.centro_custo_departamento.trim().length > 0 && (endPointResponse.data.categoria == 'INFRAESTRUTURA' && endPointResponse.data.subcategoria == 'INTERNET')) {
|
||||
|
||||
centro_de_custo = endPointResponse.data.centro_custo_departamento
|
||||
|
||||
msg_endpoint2 = await queryEndPointHit(centro_de_custo)
|
||||
}
|
||||
|
||||
|
||||
const itsm_response = async (message1: string = '', message2: string = '') => {
|
||||
|
||||
// OLD
|
||||
// const msg = await wbot.sendMessage(`${contact.number}@c.us`, `*Situação do chamado ${extractCallCode(msgAction.msgBody)}:*${message1}${msg_endpoint_response}${message2}\n_Digite *0* para voltar ao menu principal._`);
|
||||
// await verifyMessage(msg, ticket, contact);
|
||||
// await new Promise(f => setTimeout(f, 1000));
|
||||
|
||||
// NEW
|
||||
await SendWhatsAppMessage({ body: `*Situação do chamado ${extractCallCode(msgAction.msgBody)}:*${message1}${msg_endpoint_response}${message2}\n_Digite *0* para voltar ao menu principal._`, ticket, number: `${contact.number}@c.us` })
|
||||
botSendMessage(ticket, `Protocolo *${params[1]}* não encontrado!\n_Digite *0* para falar com a HIT._`)
|
||||
|
||||
}
|
||||
else if (valid && valid.data.result == 'close') {
|
||||
|
||||
botSendMessage(
|
||||
ticket,
|
||||
`O protocolo *${params[1]}* foi encerrado. Não é mais possível adicionar informação. Se desejar consultar o historico digite *1*`)
|
||||
|
||||
const sendMessageBot = async (message1: string = '', message2: string = '') => {
|
||||
|
||||
// OLD
|
||||
// const msg = await wbot.sendMessage(`${contact.number}@c.us`, `${message1}${message2}`);
|
||||
// await verifyMessage(msg, ticket, contact);
|
||||
// await new Promise(f => setTimeout(f, 1000));
|
||||
|
||||
// NEW
|
||||
await SendWhatsAppMessage({ body: `${message1}${message2}`, ticket, number: `${contact.number}@c.us` })
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (body.search('dialog_options') != -1) {
|
||||
|
||||
let msgAction = botMsgActions(body)
|
||||
|
||||
let index = msgAction.actions.findIndex((i) => i == 'dialog_options')
|
||||
|
||||
if (index != -1) {
|
||||
|
||||
let dialog_options = msgAction.actions[index + 1]
|
||||
|
||||
if (dialog_options == '3' && endPointResponse.data.categoria == 'ELOS') {
|
||||
|
||||
index = msgAction.actions.findIndex((i) => i == 'queue_transfer')
|
||||
|
||||
if (index != -1) {
|
||||
|
||||
await itsm_response('\n\n')
|
||||
|
||||
await monitoramento_response2(msg_endpoint2, wbot, contact, ticket, centro_de_custo, '\n\n', false)
|
||||
|
||||
botSendMessage(ticket, contact, wbot, `Estamos direcionando seu atendimento para o Suporte. Em breve você será atendido por um de nossos atendentes!\n\nPara voltar ao atendimento *automatizado* e sair da fila de atendimento *humano* digite *0*`)
|
||||
|
||||
await transferTicket(+msgAction.actions[index + 1], wbot, ticket, contact)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if (
|
||||
|
||||
(endPointResponse.data.categoria == 'INFRAESTRUTURA' && endPointResponse.data.subcategoria == 'INTERNET' &&
|
||||
endPointResponse.data.terceiro_nivel == 'QUEDA TOTAL') ||
|
||||
|
||||
(endPointResponse.data.categoria == 'INFRAESTRUTURA' && endPointResponse.data.subcategoria == 'INTERNET' &&
|
||||
endPointResponse.data.terceiro_nivel == 'PROBLEMA DE LENTIDÃO') ||
|
||||
|
||||
(endPointResponse.data.categoria == 'ELOS' && endPointResponse.data.subcategoria == 'VENDAS') ||
|
||||
|
||||
(endPointResponse.data.categoria == 'ELOS' && endPointResponse.data.subcategoria == 'INDISPONIBILIDADE')
|
||||
|
||||
) {
|
||||
|
||||
await itsm_response('\n\n')
|
||||
|
||||
if (endPointResponse.data.categoria == 'INFRAESTRUTURA' && endPointResponse.data.subcategoria == 'INTERNET' && centro_de_custo) {
|
||||
await monitoramento_response2(msg_endpoint2, wbot, contact, ticket, centro_de_custo, '\n\n _Digite *0* para voltar ao menu principal._', true)
|
||||
}
|
||||
|
||||
await sendMessageBot('Se deseja solicitar atendimento de urgência, digite *1*!', '\n\n _Digite *0* para voltar ao menu principal._')
|
||||
|
||||
return
|
||||
//
|
||||
|
||||
}
|
||||
else {
|
||||
//await sendMessageBot('A categorização desse chamado não se enquadra no atendimento deste canal!', '\n\n _Digite *0* para voltar ao menu principal._')
|
||||
await itsm_response('\n\n')
|
||||
|
||||
if (endPointResponse.data.categoria == 'INFRAESTRUTURA' && endPointResponse.data.subcategoria == 'INTERNET' && centro_de_custo) {
|
||||
await monitoramento_response2(msg_endpoint2, wbot, contact, ticket, centro_de_custo, '\n\n _Digite *0* para voltar ao menu principal._', true)
|
||||
}
|
||||
botSendMessage(ticket, `Ops! Não foi possível validar seu protocolo devido a um erro na comunicação com o servidor.Tente novamente mais tarde.\n_Digite *0* para falar com a HIT._`)
|
||||
|
||||
await sendMessageBot('Acompanhe a evolução do atendimento através do SOS')
|
||||
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// else if ((endPointResponse.data.categoria == 'INFRAESTRUTURA' || endPointResponse.data.subcategoria == 'INTERNET' ||
|
||||
// endPointResponse.data.terceiro_nivel == 'QUEDA TOTAL' || endPointResponse.data.terceiro_nivel == 'PROBLEMA DE LENTIDÃO') ||
|
||||
// (endPointResponse.data.terceiro_nivel == 'PROBLEMA DE LENTIDÃO' || endPointResponse.data.terceiro_nivel == 'ABERTO')) {
|
||||
}
|
||||
|
||||
// await itsm_response('', `\n Estamos direcionando seu atendimento para o Suporte. Em breve você será atendido por um de nossos atendentes!`)
|
||||
if (params[0] === 'validate_n_chamado_web') return
|
||||
|
||||
// await monitoramento_response(msg_endpoint2)
|
||||
if (params[0] === 'cod_web') {
|
||||
|
||||
// await transferTicket(0, wbot, ticket, contact)
|
||||
response = await endPointQuery('http://177.107.192.247:8095/labs/monitoramentohit/api/api.php',
|
||||
'post', {
|
||||
'params[cod_web]': params[1],
|
||||
'method': 'omnihit.consultachamado'
|
||||
})
|
||||
|
||||
// }
|
||||
// else {
|
||||
|
||||
// await itsm_response('', `\n Por favor, aguarde atendimento e acompanhe sua solicitação no SOS.`)
|
||||
|
||||
// await monitoramento_response(msg_endpoint2)
|
||||
|
||||
// }
|
||||
|
||||
}
|
||||
else if (endPointResponse && endPointResponse.status == 200 && Object.entries(endPointResponse.data).length == 0) {
|
||||
botSendMessage(ticket, contact, wbot, `Não existe nenhum chamado para consulta com esse número!\n _Digite *0* para voltar ao menu principal._`)
|
||||
return
|
||||
else if (params[0] === 'n_chamado_web') {
|
||||
|
||||
response = await endPointQuery('http://177.107.192.247:8095/labs/monitoramentohit/api/api.php',
|
||||
'post',
|
||||
{
|
||||
'params[n_chamado_web]': params[1],
|
||||
'method': 'omnihit.consultachamado',
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
else if (endPointResponse && endPointResponse.status == 500) {
|
||||
botSendMessage(ticket, contact, wbot, `Houve um erro ao realizar a consulta no sos espacolaser!\n _Digite *0* para voltar ao menu principal._`)
|
||||
return
|
||||
}
|
||||
else {
|
||||
botSendMessage(ticket, contact, wbot, `Desculpe, nao foi possível realizar a consulta!\n _Digite *0* para voltar ao menu principal._`)
|
||||
return
|
||||
|
||||
try {
|
||||
|
||||
if (response && response.data.result.trim().length > 0) {
|
||||
response = response.data.result
|
||||
}
|
||||
else if (response && response.data.result.trim().length === 0) {
|
||||
response = ''
|
||||
}
|
||||
else {
|
||||
response = null
|
||||
}
|
||||
|
||||
// response = response.data.result
|
||||
|
||||
if (response.trim().length == 0) {
|
||||
|
||||
botSendMessage(ticket, `Não existe nenhum chamado para essa operação!\n _Digite *0* para falar com a HIT._`)
|
||||
|
||||
}
|
||||
else if (response.trim().length > 0) {
|
||||
|
||||
await SendWhatsAppMessage({ body: response, ticket });
|
||||
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
botSendMessage(ticket, `Houve um erro ao realizar a consulta!\n _Digite *0* para falar com a HIT._`)
|
||||
}
|
||||
|
||||
} else if (msgAction.actions[0] == 'queue_transfer') {
|
||||
|
||||
console.log('>>>>>>>>>>>>>>> msgAction: ', msgAction, ' | msgAction.actions[1]: ', msgAction.actions[1])
|
||||
|
||||
// const contact_custom_field = await ShowContactCustomFieldService(contact.id)
|
||||
const contact_custom_field = await ShowContactCustomFieldService(contact.id)
|
||||
|
||||
// if (contact_custom_field && contact_custom_field.length > 0) {
|
||||
if (contact_custom_field && contact_custom_field.length > 0) {
|
||||
|
||||
// const msg_endpoint = await queryEndPointHit(contact_custom_field[0].value)
|
||||
const msg_endpoint = await queryEndPointHit(contact_custom_field[0].value)
|
||||
|
||||
// await monitoramento_response2(msg_endpoint, wbot, contact, ticket, contact_custom_field[0].value)
|
||||
await monitoramento_response2(msg_endpoint, wbot, contact, ticket, contact_custom_field[0].value)
|
||||
|
||||
// }
|
||||
}
|
||||
|
||||
// console.log('************* contact_custom_field: ', contact_custom_field)
|
||||
console.log('************* contact_custom_field: ', contact_custom_field)
|
||||
|
||||
// OLD
|
||||
// const msg = await wbot.sendMessage(`${contact.number}@c.us`, msgAction.msgBody);
|
||||
|
@ -592,20 +555,22 @@ const extractCallCode = (str: string) => {
|
|||
return ''
|
||||
}
|
||||
|
||||
const sendDialogflowAwswer = async (
|
||||
wbot: Session,
|
||||
const sendDialogflowAnswer = async (
|
||||
wbot: any,
|
||||
ticket: Ticket,
|
||||
msg: any,
|
||||
contact: Contact,
|
||||
chat: Chat,
|
||||
startDialog: boolean = false
|
||||
startDialog: boolean = false,
|
||||
send: boolean = true
|
||||
// chat: Chat
|
||||
) => {
|
||||
|
||||
if (startDialog){
|
||||
if (startDialog) {
|
||||
msg.body = 'menu'
|
||||
console.log('<--------------------- VOLTOU AO MENU ---------------->')
|
||||
}
|
||||
|
||||
|
||||
|
||||
console.log('uuuuuuuuuuuuuuuuuuuuuuuuuuu 04')
|
||||
|
||||
|
@ -620,14 +585,14 @@ const sendDialogflowAwswer = async (
|
|||
console.log('uuuuuuuuuuuuuuuuuuuuuuuuuuu 4')
|
||||
|
||||
if (msg.type != 'chat') {
|
||||
botSendMessage(ticket, contact, wbot, `Desculpe, nao compreendi!\nEnvie apenas texto quando estiver interagindo com o bot!\n _Digite *0* para voltar ao menu principal._`)
|
||||
botSendMessage(ticket, `Desculpe, nao compreendi!\nEnvie apenas texto quando estiver interagindo com o bot!\n _Digite *0* para falar com a HIT._`)
|
||||
return
|
||||
}
|
||||
|
||||
console.log('uuuuuuuuuuuuuuuuuuuuuuuuuuu 5')
|
||||
|
||||
if (msg.type == 'chat' && String(msg.body).length > 120) {
|
||||
botSendMessage(ticket, contact, wbot, `Desculpe, nao compreendi!\nTexto acima de 120 caracteres!\n _Digite *0* para voltar ao menu principal._`)
|
||||
botSendMessage(ticket, `Desculpe, nao compreendi!\nTexto acima de 120 caracteres!\n _Digite *0* para falar com a HIT._`)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -644,8 +609,10 @@ const sendDialogflowAwswer = async (
|
|||
return;
|
||||
}
|
||||
|
||||
if (!send) return
|
||||
|
||||
// Make disponible later from session out
|
||||
// chat.sendStateTyping();
|
||||
// chat.sendStateTyping();
|
||||
|
||||
await new Promise(f => setTimeout(f, 1000));
|
||||
|
||||
|
@ -772,12 +739,11 @@ const verifyQueue = async (
|
|||
console.log('uuuuuuuuuuuuuuuuuuuuuuuuuuu 3')
|
||||
|
||||
const chat = wbot.chat
|
||||
await sendDialogflowAwswer(wbot, _ticket, msg, contact, chat, aceppt);
|
||||
await sendDialogflowAnswer(wbot, _ticket, msg, contact, chat, aceppt);
|
||||
|
||||
console.log('uuuuuuuuuuuuuuuuuuuuuuuuuuu 03')
|
||||
return
|
||||
|
||||
|
||||
}
|
||||
//
|
||||
|
||||
|
@ -792,9 +758,6 @@ const verifyQueue = async (
|
|||
body = `\u200e${choosenQueue.greetingMessage}`;
|
||||
}
|
||||
|
||||
// const sentMessage = await wbot.sendMessage(`${contact.number}@c.us`, body);
|
||||
// await verifyMessage(sentMessage, ticket, contact);
|
||||
|
||||
sendWhatsAppMessageSocket(ticket, body)
|
||||
|
||||
// console.log('uuuuuuuuuuuuuuuuuuuuuuuuuuu 3 body: ',body)
|
||||
|
@ -802,10 +765,9 @@ const verifyQueue = async (
|
|||
}
|
||||
else {
|
||||
|
||||
const repet: any = await mostRepeatedPhrase(ticket.id)
|
||||
|
||||
//test del transfere o atendimento se entrar na ura infinita
|
||||
let ticket_message = await ShowTicketMessage(ticket.id, false);
|
||||
if (ticket_message.length > 20) {
|
||||
if (repet.occurrences > 4) {
|
||||
|
||||
await UpdateTicketService({ ticketData: { status: 'pending', queueId: queues[0].id }, ticketId: ticket.id });
|
||||
|
||||
|
@ -835,8 +797,8 @@ const verifyQueue = async (
|
|||
|
||||
bodySplited.forEach(e => {
|
||||
|
||||
if(e && e.trim().length>0){
|
||||
console.log('ELEMENT e: ',e)
|
||||
if (e && e.trim().length > 0) {
|
||||
console.log('ELEMENT e: ', e)
|
||||
sendWhatsAppMessageSocket(ticket, e)
|
||||
}
|
||||
|
||||
|
@ -858,7 +820,7 @@ const verifyQueue = async (
|
|||
}
|
||||
};
|
||||
|
||||
const transferTicket = async (queueIndex: number, wbot: Session, ticket: Ticket, contact: Contact) => {
|
||||
const transferTicket = async (queueIndex: number, wbot: any, ticket: Ticket, contact: Contact) => {
|
||||
|
||||
const botInfo = await BotIsOnQueue('botqueue', contact.accept)
|
||||
|
||||
|
@ -868,10 +830,13 @@ const transferTicket = async (queueIndex: number, wbot: Session, ticket: Ticket,
|
|||
|
||||
// console.log('queues ---> ', queues)
|
||||
|
||||
await botTransferTicket(queues[queueIndex], ticket, contact, wbot)
|
||||
await botTransferTicket(queues[queueIndex], ticket)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// const botMsgActions = (params: string) => {
|
||||
|
||||
// let lstActions = params.split('dialog_actions=')
|
||||
|
@ -914,7 +879,7 @@ const isValidMsg = (msg: WbotMessage): boolean => {
|
|||
};
|
||||
|
||||
|
||||
const queuesOutBot = async (wbot: Session, botId: string | number) => {
|
||||
const queuesOutBot = async (wbot: any, botId: string | number) => {
|
||||
|
||||
const { queues, greetingMessage } = await ShowWhatsAppService(wbot.id!);
|
||||
|
||||
|
@ -928,7 +893,9 @@ const queuesOutBot = async (wbot: Session, botId: string | number) => {
|
|||
|
||||
}
|
||||
|
||||
const botTransferTicket = async (queues: Queue, ticket: Ticket, contact: Contact, wbot: Session) => {
|
||||
const botTransferTicket = async (queues: Queue, ticket: Ticket) => {
|
||||
|
||||
console.log('>>>>>>>>>>>>>>>>> queues.id: ', queues.id)
|
||||
|
||||
await ticket.update({ userId: null });
|
||||
|
||||
|
@ -936,7 +903,7 @@ const botTransferTicket = async (queues: Queue, ticket: Ticket, contact: Contact
|
|||
|
||||
}
|
||||
|
||||
const botSendMedia = async (ticket: Ticket, contact: Contact, wbot: Session, mediaPath: string, fileNameExtension: string) => {
|
||||
const botSendMedia = async (ticket: Ticket, contact: Contact, wbot: any, mediaPath: string, fileNameExtension: string) => {
|
||||
|
||||
const debouncedSentMessage = debounce(
|
||||
|
||||
|
@ -965,7 +932,7 @@ const botSendMedia = async (ticket: Ticket, contact: Contact, wbot: Session, med
|
|||
}
|
||||
|
||||
|
||||
const botSendMessage = (ticket: Ticket, contact: Contact, wbot: Session, msg: string) => {
|
||||
const botSendMessage = (ticket: Ticket, msg: string) => {
|
||||
|
||||
const debouncedSentMessage = debounce(
|
||||
|
||||
|
@ -1016,7 +983,7 @@ const handleMessage = async (
|
|||
|
||||
if (index == -1) {
|
||||
|
||||
// console.log('-----------------> LST: ', lst)
|
||||
// console.log('-----------------> LST: ', lst):q
|
||||
|
||||
lst.push({ id: msg.id.id })
|
||||
|
||||
|
@ -1107,6 +1074,12 @@ const handleMessage = async (
|
|||
// const chat = await msg.getChat();
|
||||
const chat = wbot.chat
|
||||
|
||||
// if(chat.isGroup){
|
||||
|
||||
// console.log('This message is from a Group and will be ignored!')
|
||||
// return
|
||||
// }
|
||||
|
||||
// console.log('----------> chat: ', JSON.parse(JSON.stringify(chat)))
|
||||
|
||||
// if (chat.isGroup) {
|
||||
|
@ -1129,7 +1102,7 @@ const handleMessage = async (
|
|||
|
||||
const unreadMessages = msg.fromMe ? 0 : chat.unreadCount;
|
||||
|
||||
const contact = await verifyContact(msgContact);
|
||||
const contact: any = await verifyContact(msgContact);
|
||||
|
||||
|
||||
// console.log('----------> contact: ', JSON.parse(JSON.stringify(contact)))
|
||||
|
@ -1145,15 +1118,53 @@ const handleMessage = async (
|
|||
// }
|
||||
|
||||
|
||||
let ticket
|
||||
|
||||
if (unreadMessages === 0 && whatsapp.farewellMessage && whatsapp.farewellMessage === msg.body) return;
|
||||
const _botInfo = await BotIsOnQueue('botqueue')
|
||||
|
||||
if (_botInfo.isOnQueue) {
|
||||
|
||||
let ticket_obj: any = await FindOrCreateTicketServiceBot(
|
||||
contact,
|
||||
wbot.id!,
|
||||
unreadMessages,
|
||||
// groupContact
|
||||
);
|
||||
|
||||
ticket = ticket_obj.ticket
|
||||
|
||||
if (ticket_obj.created) {
|
||||
|
||||
let queue = await ShowQueueService(_botInfo.botQueueId);
|
||||
|
||||
await UpdateTicketService({
|
||||
ticketData: { queueId: queue.id },
|
||||
ticketId: ticket.id
|
||||
});
|
||||
|
||||
ticket = await ShowTicketService(ticket.id);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else {
|
||||
ticket = await FindOrCreateTicketService(
|
||||
contact,
|
||||
wbot.id!,
|
||||
unreadMessages,
|
||||
// groupContact
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// const ticket = await FindOrCreateTicketService(
|
||||
// contact,
|
||||
// wbot.id!,
|
||||
// unreadMessages,
|
||||
// // groupContact
|
||||
// );
|
||||
|
||||
const ticket = await FindOrCreateTicketService(
|
||||
contact,
|
||||
wbot.id!,
|
||||
unreadMessages,
|
||||
// groupContact
|
||||
);
|
||||
|
||||
//
|
||||
// await updateTicketCacheByTicketId(ticket.id, {'contact.profilePicUrl': ticket.contact.profilePicUrl})
|
||||
|
@ -1190,9 +1201,7 @@ const handleMessage = async (
|
|||
!ticket.userId &&
|
||||
whatsapp.queues.length >= 1
|
||||
) {
|
||||
|
||||
await verifyQueue(wbot, msg, ticket, contact);
|
||||
|
||||
}
|
||||
|
||||
// O bot interage com o cliente e encaminha o atendimento para fila de atendende quando o usuário escolhe a opção falar com atendente
|
||||
|
@ -1202,40 +1211,75 @@ const handleMessage = async (
|
|||
// const botInfo = { isOnQueue: false, botQueueId: 0, userIdBot: 0 }
|
||||
if (botInfo.isOnQueue && !msg.fromMe && ticket.userId == botInfo.userIdBot) {
|
||||
|
||||
// TEST DEL
|
||||
let test: any = await ShowTicketMessage(ticket.id, false, true, 5);
|
||||
const repet: any = await mostRepeatedPhrase(ticket.id)
|
||||
|
||||
if (test && test.length > 0 && test[0].body.includes('Se deseja solicitar atendimento de urgência, digite *1*') && msg.body == '1') {
|
||||
console.log('repet.occurrences: ', repet.occurrences)
|
||||
|
||||
console.log('===================================> ENDPOINT REQUEST')
|
||||
if (repet.occurrences > 4) {
|
||||
|
||||
for (let i = 0; i < test.length; i++) {
|
||||
await transferTicket(0, wbot, ticket, contact.accept)
|
||||
|
||||
if (test[i].body.includes('*categoria*: INFRAESTRUTURA')) {
|
||||
await SendWhatsAppMessage({
|
||||
body: `Seu atendimento foi transferido para um agente!\n\nPara voltar ao menu principal digite *0*
|
||||
`, ticket, number: `${contact.number}@c.us`
|
||||
})
|
||||
|
||||
botSendMessage(ticket, contact, wbot, `Estamos direcionando seu atendimento para o Suporte. Em breve você será atendido por um de nossos atendentes!\n\nPara voltar ao atendimento *automatizado* e sair da fila de atendimento *humano* digite *0*`)
|
||||
}
|
||||
else {
|
||||
|
||||
await transferTicket(0, wbot, ticket, contact)
|
||||
break
|
||||
let last_messages = await ShowTicketMessage(ticket.id, 2, true)
|
||||
|
||||
if (last_messages.length > 0 && last_messages[0].body.includes('validado') && msg.body.trim() != '0') {
|
||||
|
||||
// botSendMessage(ticket,`Aguarde, inserindo informação...\n_Digite *0* para falar com a HIT._`)
|
||||
|
||||
await SendWhatsAppMessage({ body: `Aguarde inserindo informação, em breve te atualizaremos`, ticket })
|
||||
|
||||
|
||||
let aux_msg = last_messages[0].body
|
||||
|
||||
aux_msg = aux_msg.split('\n')[0]
|
||||
|
||||
let index = aux_msg.indexOf('do protocolo ')
|
||||
|
||||
aux_msg = aux_msg.substring(index, aux_msg.length)
|
||||
|
||||
let regex = /[0-9-]+/g;
|
||||
|
||||
let matches: any = aux_msg.match(regex);
|
||||
|
||||
console.log("~~~~~~~~~~~~~~~~~~~~~~> matches.join(''): ", matches.join(''));
|
||||
|
||||
let response = await endPointQuery(
|
||||
'http://177.107.192.247:8095/labs/monitoramentohit/api/api.php',
|
||||
'post',
|
||||
{
|
||||
'params[n_chamado_web]': matches.join(''),
|
||||
'method': 'omnihit.chamadoaddobs',
|
||||
'params[obs]': msg.body
|
||||
})
|
||||
|
||||
if (response && response.data.result) {
|
||||
|
||||
botSendMessage(ticket, `${response.data.result}`)
|
||||
|
||||
}
|
||||
else if (test[i].body.includes('*categoria*: ELOS')) {
|
||||
else {
|
||||
|
||||
botSendMessage(ticket, contact, wbot, `Estamos direcionando seu atendimento para o Suporte. Em breve você será atendido por um de nossos atendentes!\n\nPara voltar ao atendimento *automatizado* e sair da fila de atendimento *humano* digite *0*`)
|
||||
botSendMessage(ticket, `Ops! Houve um erro ao tentar inserir sua informação devido a um erro na comunicação com o servidor.Tente novamente mais tarde.\n_Digite *0* para falar com a HIT._`)
|
||||
|
||||
await transferTicket(1, wbot, ticket, contact)
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
await sendDialogflowAnswer(wbot, ticket, msg, contact, chat, contact.accept);
|
||||
|
||||
}
|
||||
|
||||
|
||||
return
|
||||
}
|
||||
//
|
||||
|
||||
await sendDialogflowAwswer(wbot, ticket, msg, contact, chat);
|
||||
|
||||
}
|
||||
else if (botInfo.isOnQueue && !msg.fromMe && msg.body == '0' && ticket.status == 'pending' && ticket.queueId) {
|
||||
|
||||
|
@ -1251,54 +1295,28 @@ const handleMessage = async (
|
|||
// const chat = await msg.getChat();
|
||||
const chat = wbot.chat
|
||||
|
||||
await sendDialogflowAwswer(wbot, _ticket, msg, contact, chat);
|
||||
await sendDialogflowAnswer(wbot, _ticket, msg, contact, chat, contact.aceppt);
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// if (msg.body.trim() == 'broken') {
|
||||
// throw new Error('Throw makes it go boom!')
|
||||
// }
|
||||
//
|
||||
if (msg && !msg.fromMe && ticket.status == 'pending') {
|
||||
|
||||
await setMessageAsRead(ticket)
|
||||
|
||||
}
|
||||
|
||||
|
||||
} catch (err) {
|
||||
Sentry.captureException(err);
|
||||
console.log('xxxxxxxxxxxxx err: ', err)
|
||||
logger.error(`Error handling whatsapp message: Err: ${err}`);
|
||||
|
||||
const whatsapp = await ShowWhatsAppService(wbot.id!);
|
||||
|
||||
//Solução para contornar erro de sessão
|
||||
if ((`${err}`).includes("Evaluation failed: r")) {
|
||||
|
||||
const sourcePath = path.join(__dirname, `../../../.wwebjs_auth/sessions/log`)
|
||||
|
||||
let log = new Date(new Date() + 'UTC');
|
||||
const dateToday = splitDateTime(new Date(format(new Date(), 'yyyy-MM-dd HH:mm:ss', { locale: ptBR })))
|
||||
|
||||
if (whatsapp.status == 'CONNECTED') {
|
||||
|
||||
|
||||
|
||||
let timestamp = Math.floor(Date.now() / 1000)
|
||||
|
||||
fs.writeFile(`${sourcePath}/${timestamp}_wbotMessageListener.txt`, `Whatsapp id: ${whatsapp.id} \nDate: ${dateToday.fullDate} ${dateToday.fullTime} \nFile: wbotMessageListener.ts \nError: ${err}`, (error) => { });
|
||||
|
||||
// await restartWhatsSession(whatsapp)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else if (`${err}`.includes('[object Object]')) {
|
||||
|
||||
await _restore(whatsapp, 'auto_object_error')
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
const handleMsgAck = async (msg_id: any, ack: any) => {
|
||||
await new Promise(r => setTimeout(r, 500));
|
||||
|
||||
await new Promise(r => setTimeout(r, 4000));
|
||||
|
||||
const io = getIO();
|
||||
|
||||
|
@ -1314,6 +1332,7 @@ const handleMsgAck = async (msg_id: any, ack: any) => {
|
|||
]
|
||||
});
|
||||
if (!messageToUpdate) {
|
||||
console.log(`Not found the MESSAGE ID ${msg_id}to change the ACK into the Message table`)
|
||||
return;
|
||||
}
|
||||
await messageToUpdate.update({ ack });
|
||||
|
@ -1331,19 +1350,19 @@ const handleMsgAck = async (msg_id: any, ack: any) => {
|
|||
}
|
||||
};
|
||||
|
||||
const wbotMessageListener = (wbot: Session): void => {
|
||||
const wbotMessageListener = (wbot: any): void => {
|
||||
|
||||
wbot.on("message_create", async msg => {
|
||||
wbot.on("message_create", async (msg: any) => {
|
||||
handleMessage(msg, wbot);
|
||||
});
|
||||
|
||||
wbot.on("media_uploaded", async msg => {
|
||||
wbot.on("media_uploaded", async (msg: any) => {
|
||||
handleMessage(msg, wbot);
|
||||
});
|
||||
|
||||
wbot.on("message_ack", async (msg, ack) => {
|
||||
wbot.on("message_ack", async (msg: any, ack: any) => {
|
||||
handleMsgAck(msg, ack);
|
||||
});
|
||||
};
|
||||
|
||||
export { wbotMessageListener, handleMessage, handleMsgAck, lst };
|
||||
export { wbotMessageListener, handleMessage, handleMsgAck, lst, verifyContact, sendDialogflowAnswer };
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,156 @@
|
|||
import React, { useState, useEffect, useContext, useRef, useCallback } from "react";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import { toast } from "react-toastify";
|
||||
|
||||
import Button from "@material-ui/core/Button";
|
||||
import Dialog from "@material-ui/core/Dialog";
|
||||
import Select from "@material-ui/core/Select";
|
||||
import FormControl from "@material-ui/core/FormControl";
|
||||
import InputLabel from "@material-ui/core/InputLabel";
|
||||
import MenuItem from "@material-ui/core/MenuItem";
|
||||
import LinearProgress from "@material-ui/core/LinearProgress";
|
||||
import { makeStyles } from "@material-ui/core";
|
||||
|
||||
import DialogActions from "@material-ui/core/DialogActions";
|
||||
import DialogContent from "@material-ui/core/DialogContent";
|
||||
import DialogTitle from "@material-ui/core/DialogTitle";
|
||||
|
||||
import { i18n } from "../../translate/i18n";
|
||||
import ButtonWithSpinner from "../ButtonWithSpinner";
|
||||
import { AuthContext } from "../../context/Auth/AuthContext";
|
||||
|
||||
import toastError from "../../errors/toastError";
|
||||
|
||||
import api from "../../services/api";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
maxWidth: {
|
||||
width: "100%",
|
||||
},
|
||||
paper: {
|
||||
minWidth: "300px"
|
||||
},
|
||||
linearProgress: {
|
||||
marginTop: "5px"
|
||||
}
|
||||
}));
|
||||
|
||||
const ContactCreateTicketModal = ({ modalOpen, onClose, contactId }) => {
|
||||
const { user } = useContext(AuthContext);
|
||||
let isMounted = useRef(true)
|
||||
|
||||
const history = useHistory();
|
||||
const [queues, setQueues] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [selectedQueue, setSelectedQueue] = useState('');
|
||||
const [itemHover, setItemHover] = useState(-1)
|
||||
const classes = useStyles();
|
||||
|
||||
useEffect(() => {
|
||||
const userQueues = user.queues.map(({ id, name, color }) => { return { id, name, color } })
|
||||
if (userQueues.length === 1) setSelectedQueue(userQueues[0].id)
|
||||
setQueues(userQueues)
|
||||
}, [user]);
|
||||
|
||||
const handleClose = () => {
|
||||
onClose();
|
||||
};
|
||||
|
||||
const handleSaveTicket = useCallback(async (contactId, userId, queueId) => {
|
||||
if (!contactId || !userId) {
|
||||
console.log("Missing contactId or userId")
|
||||
return
|
||||
};
|
||||
if (!queueId) {
|
||||
toast.warning("Nenhuma Fila Selecionada")
|
||||
return
|
||||
}
|
||||
if (isMounted.current) setLoading(true);
|
||||
|
||||
|
||||
const delayDebounceFn = setTimeout(() => {
|
||||
const ticketCreate = async () => {
|
||||
try {
|
||||
const { data: ticket } = await api.post("/tickets", {
|
||||
contactId: contactId,
|
||||
userId: userId,
|
||||
queueId: queueId,
|
||||
status: "open",
|
||||
});
|
||||
history.push(`/tickets/${ticket.id}`);
|
||||
} catch (err) {
|
||||
toastError(err);
|
||||
}
|
||||
if (isMounted.current) setLoading(false);
|
||||
|
||||
};
|
||||
ticketCreate();
|
||||
}, 300);
|
||||
return () => clearTimeout(delayDebounceFn);
|
||||
|
||||
}, [history])
|
||||
|
||||
useEffect(() => {
|
||||
if (modalOpen && queues.length <= 1) {
|
||||
handleSaveTicket(contactId, user.id, selectedQueue)
|
||||
}
|
||||
return () => {
|
||||
isMounted.current = false;
|
||||
};
|
||||
}, [modalOpen, contactId, user.id, selectedQueue, handleSaveTicket, queues.length]);
|
||||
|
||||
if (modalOpen && queues.length <= 1) {
|
||||
return <LinearProgress />
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog open={modalOpen} onClose={handleClose} maxWidth="xs" scroll="paper" classes={{ paper: classes.paper }}>
|
||||
<DialogTitle id="form-dialog-title">
|
||||
{i18n.t("newTicketModal.title")}
|
||||
</DialogTitle>
|
||||
<DialogContent dividers>
|
||||
<FormControl variant="outlined" className={classes.maxWidth}>
|
||||
<InputLabel>{i18n.t("Selecionar Fila")}</InputLabel>
|
||||
<Select
|
||||
value={selectedQueue}
|
||||
onChange={(e) => setSelectedQueue(e.target.value)}
|
||||
label={i18n.t("Filas")}
|
||||
>
|
||||
<MenuItem value={''}> </MenuItem>
|
||||
{queues.map(({ id, color, name }) => (
|
||||
<MenuItem
|
||||
key={id}
|
||||
value={id}
|
||||
onMouseEnter={() => setItemHover(id)}
|
||||
onMouseLeave={() => setItemHover(-1)}
|
||||
style={{
|
||||
background: id !== itemHover ? "white" : color,
|
||||
}}
|
||||
>{name[0].toUpperCase() + name.slice(1).toLowerCase()}</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
onClick={handleClose}
|
||||
color="secondary"
|
||||
disabled={loading}
|
||||
variant="outlined"
|
||||
>
|
||||
{i18n.t("newTicketModal.buttons.cancel")}
|
||||
</Button>
|
||||
<ButtonWithSpinner
|
||||
onClick={() => handleSaveTicket(contactId, user.id, selectedQueue)}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
loading={loading}
|
||||
>
|
||||
{i18n.t("newTicketModal.buttons.ok")}
|
||||
</ButtonWithSpinner>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default ContactCreateTicketModal;
|
|
@ -1,8 +1,9 @@
|
|||
import React, { useState, useEffect, useReducer, useRef } from "react";
|
||||
import React, { useContext, useState, useEffect, useReducer, useRef } from "react";
|
||||
|
||||
import { isSameDay, parseISO, format } from "date-fns";
|
||||
import openSocket from "socket.io-client";
|
||||
import clsx from "clsx";
|
||||
import { AuthContext } from "../../context/Auth/AuthContext";
|
||||
|
||||
import { green } from "@material-ui/core/colors";
|
||||
import {
|
||||
|
@ -318,6 +319,9 @@ const MessagesList = ({ ticketId, isGroup }) => {
|
|||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
const messageOptionsMenuOpen = Boolean(anchorEl);
|
||||
const currentTicketId = useRef(ticketId);
|
||||
const [sendSeen, setSendSeen] = useState(false)
|
||||
|
||||
const { user } = useContext(AuthContext);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch({ type: "RESET" });
|
||||
|
@ -327,13 +331,77 @@ const MessagesList = ({ ticketId, isGroup }) => {
|
|||
}, [ticketId]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
let url_split
|
||||
let url_ticketId
|
||||
|
||||
try {
|
||||
|
||||
url_split = window.location.href.split('tickets')
|
||||
|
||||
url_ticketId = url_split[url_split.length - 1].match(/\d+/)[0]
|
||||
|
||||
} catch (error) {
|
||||
console.log('error on try do the send seen: ', error)
|
||||
}
|
||||
|
||||
if (!url_ticketId) return
|
||||
|
||||
if (!sendSeen) return
|
||||
|
||||
const delayDebounceFn = setTimeout(() => {
|
||||
const sendSeenMessage = async () => {
|
||||
try {
|
||||
const { data } = await api.get("/messages/" + ticketId, {
|
||||
params: { pageNumber },
|
||||
});
|
||||
|
||||
setSendSeen(false)
|
||||
|
||||
if (!data) return
|
||||
|
||||
if (data.ticket.status === "open" && /*data.ticket.unreadMessages > 0 &&*/
|
||||
data.ticket.userId === user.id) {
|
||||
|
||||
let fromMe = false
|
||||
|
||||
if (data.messages.length > 0) {
|
||||
fromMe = data.messages[data.messages.length - 1].fromMe
|
||||
}
|
||||
|
||||
// Atualiza Unread messages para 0
|
||||
// Atualizei função no back-end para receber o novo parametro unreadMessages
|
||||
const ticketUpdate = { ...data.ticket, unreadMessages: 0, fromMe }
|
||||
await api.put("/tickets/" + ticketId, ticketUpdate)
|
||||
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
setLoading(false);
|
||||
toastError(err);
|
||||
}
|
||||
};
|
||||
sendSeenMessage();
|
||||
}, 500);
|
||||
|
||||
|
||||
return () => {
|
||||
clearTimeout(delayDebounceFn);
|
||||
};
|
||||
|
||||
|
||||
|
||||
}, [sendSeen, pageNumber, ticketId, user.id]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
setLoading(true);
|
||||
const delayDebounceFn = setTimeout(() => {
|
||||
const fetchMessages = async () => {
|
||||
try {
|
||||
const { data } = await api.get("/messages/" + ticketId, {
|
||||
params: { pageNumber },
|
||||
});
|
||||
});
|
||||
|
||||
if (currentTicketId.current === ticketId) {
|
||||
dispatch({ type: "LOAD_MESSAGES", payload: data.messages });
|
||||
|
@ -365,17 +433,12 @@ const MessagesList = ({ ticketId, isGroup }) => {
|
|||
|
||||
if (data.action === "create") {
|
||||
|
||||
console.log('ADD_MESSAGE: ', data.message)
|
||||
|
||||
dispatch({ type: "ADD_MESSAGE", payload: data.message });
|
||||
|
||||
scrollToBottom();
|
||||
}
|
||||
|
||||
if (data.action === "update") {
|
||||
|
||||
console.log('joinChatBox update: ',data.action)
|
||||
|
||||
dispatch({ type: "UPDATE_MESSAGE", payload: data.message });
|
||||
}
|
||||
});
|
||||
|
@ -391,7 +454,11 @@ const MessagesList = ({ ticketId, isGroup }) => {
|
|||
|
||||
const scrollToBottom = () => {
|
||||
if (lastMessageRef.current) {
|
||||
|
||||
setSendSeen(true)
|
||||
|
||||
lastMessageRef.current.scrollIntoView({});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -513,7 +580,7 @@ const MessagesList = ({ ticketId, isGroup }) => {
|
|||
if (index === messagesList.length - 1) {
|
||||
|
||||
let messageDay = parseISO(messagesList[index].createdAt);
|
||||
let previousMessageDay = parseISO(messagesList[index - 1].createdAt);
|
||||
let previousMessageDay = parseISO(messagesList[index - 1].createdAt);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -682,4 +749,4 @@ const MessagesList = ({ ticketId, isGroup }) => {
|
|||
);
|
||||
};
|
||||
|
||||
export default MessagesList;
|
||||
export default MessagesList;
|
|
@ -116,17 +116,13 @@ const NotificationsPopOver = () => {
|
|||
|
||||
const socket = openSocket(process.env.REACT_APP_BACKEND_URL);
|
||||
|
||||
socket.on("reload_page", (data) => {
|
||||
|
||||
console.log('UPDATING THE PAGE: ', data.userId, ' | user.id: ', user.id)
|
||||
socket.on("reload_page", (data) => {
|
||||
|
||||
if (user.id === data.userId) {
|
||||
|
||||
window.location.reload(true);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
@ -167,8 +163,7 @@ const NotificationsPopOver = () => {
|
|||
clearInterval(_fifo);
|
||||
}
|
||||
|
||||
_fifo = setInterval(() => {
|
||||
console.log('user.id: ', user.id)
|
||||
_fifo = setInterval(() => {
|
||||
socket.emit("online", user.id)
|
||||
}, 3000);
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import {
|
|||
|
||||
|
||||
|
||||
import { i18n } from "../../../translate/i18n";
|
||||
// import { i18n } from "../../../translate/i18n";
|
||||
|
||||
|
||||
import ptBrLocale from "date-fns/locale/pt-BR";
|
||||
|
|
|
@ -83,14 +83,14 @@ const Ticket = () => {
|
|||
const [contact, setContact] = useState({});
|
||||
const [ticket, setTicket] = useState({});
|
||||
|
||||
const [statusChatEnd, setStatusChatEnd] = useState({})
|
||||
const [statusChatEnd, setStatusChatEnd] = useState({})
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
const delayDebounceFn = setTimeout(() => {
|
||||
const fetchTicket = async () => {
|
||||
try {
|
||||
|
||||
|
||||
// maria julia
|
||||
|
||||
const { data } = await api.get("/tickets/" + ticketId);
|
||||
|
@ -101,7 +101,7 @@ const Ticket = () => {
|
|||
setContact(data.contact.contact);
|
||||
setTicket(data.contact);
|
||||
|
||||
setStatusChatEnd(data.statusChatEnd)
|
||||
setStatusChatEnd(data.statusChatEnd)
|
||||
|
||||
setLoading(false);
|
||||
} catch (err) {
|
||||
|
@ -171,8 +171,8 @@ const Ticket = () => {
|
|||
onClick={handleDrawerOpen}
|
||||
/>
|
||||
</div>
|
||||
<div className={classes.ticketActionButtons}>
|
||||
<TicketActionButtons ticket={ticket} statusChatEnd={statusChatEnd}/>
|
||||
<div className={classes.ticketActionButtons}>
|
||||
<TicketActionButtons ticket={ticket} statusChatEnd={statusChatEnd} />
|
||||
</div>
|
||||
</TicketHeader>
|
||||
<ReplyMessageProvider>
|
||||
|
|
|
@ -29,12 +29,24 @@ const useStyles = makeStyles(theme => ({
|
|||
},
|
||||
}));
|
||||
|
||||
const TicketActionButtons = ({ ticket, statusChatEnd }) => {
|
||||
const TicketActionButtons = ({ ticket, statusChatEnd }) => {
|
||||
const classes = useStyles();
|
||||
const history = useHistory();
|
||||
const history = useHistory();
|
||||
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [useDialogflow, setUseDialogflow] = useState(ticket.contact.useDialogflow);
|
||||
|
||||
// const [useDialogflow, setUseDialogflow] = useState(ticket.contact.useDialogflow);
|
||||
|
||||
// const [/*useDialogflow*/, setUseDialogflow] = useState(() => {
|
||||
// if (Object.keys(ticket).length !== 0) {
|
||||
// return ticket.contact.useDialogflow;
|
||||
// } else {
|
||||
// // Set a default value if `ticket.contact.useDialogflow` is null
|
||||
// return true
|
||||
// }
|
||||
// });
|
||||
|
||||
const ticketOptionsMenuOpen = Boolean(anchorEl);
|
||||
const { user } = useContext(AuthContext);
|
||||
|
||||
|
@ -53,9 +65,7 @@ const TicketActionButtons = ({ ticket, statusChatEnd }) => {
|
|||
|
||||
if (data) {
|
||||
|
||||
data = { ...data, 'ticketId': ticket.id }
|
||||
|
||||
|
||||
data = { ...data, 'ticketId': ticket.id }
|
||||
|
||||
handleUpdateTicketStatus(null, "closed", user?.id, data)
|
||||
|
||||
|
@ -122,17 +132,17 @@ const TicketActionButtons = ({ ticket, statusChatEnd }) => {
|
|||
|
||||
};
|
||||
|
||||
const handleContactToggleUseDialogflow = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const contact = await api.put(`/contacts/toggleUseDialogflow/${ticket.contact.id}`);
|
||||
setUseDialogflow(contact.data.useDialogflow);
|
||||
setLoading(false);
|
||||
} catch (err) {
|
||||
setLoading(false);
|
||||
toastError(err);
|
||||
}
|
||||
};
|
||||
// const handleContactToggleUseDialogflow = async () => {
|
||||
// setLoading(true);
|
||||
// try {
|
||||
// const contact = await api.put(`/contacts/toggleUseDialogflow/${ticket.contact.id}`);
|
||||
// setUseDialogflow(contact.data.useDialogflow);
|
||||
// setLoading(false);
|
||||
// } catch (err) {
|
||||
// setLoading(false);
|
||||
// toastError(err);
|
||||
// }
|
||||
// };
|
||||
|
||||
|
||||
return (
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import React, { useState, useEffect, useReducer, useContext } from "react";
|
||||
|
||||
|
||||
import openSocket from "socket.io-client";
|
||||
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
|
@ -175,7 +177,7 @@ const reducer = (state, action) => {
|
|||
};
|
||||
|
||||
const TicketsList = (props) => {
|
||||
const { status, searchParam, showAll, selectedQueueIds, updateCount, style, tab } = props;
|
||||
const { status, searchParam, searchParamContent, showAll, selectedQueueIds, updateCount, style, tab } = props;
|
||||
const classes = useStyles();
|
||||
const [pageNumber, setPageNumber] = useState(1);
|
||||
const [ticketsList, dispatch] = useReducer(reducer, []);
|
||||
|
@ -184,16 +186,16 @@ const TicketsList = (props) => {
|
|||
const { searchTicket } = useContext(SearchTicketContext)
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
dispatch({ type: "RESET" });
|
||||
setPageNumber(1);
|
||||
|
||||
}, [status, searchParam, showAll, selectedQueueIds, searchTicket]);
|
||||
|
||||
|
||||
}, [status, searchParam, searchParamContent, showAll, selectedQueueIds, searchTicket]);
|
||||
|
||||
const { tickets, hasMore, loading } = useTickets({
|
||||
pageNumber,
|
||||
searchParam,
|
||||
searchParamContent,
|
||||
status,
|
||||
showAll,
|
||||
queueIds: JSON.stringify(selectedQueueIds),
|
||||
|
@ -201,6 +203,7 @@ const TicketsList = (props) => {
|
|||
});
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
if (!status && !searchParam) return;
|
||||
|
||||
// if (searchParam) {
|
||||
|
|
|
@ -1,14 +1,21 @@
|
|||
import React, { useContext, useEffect, useRef, useState } from "react";
|
||||
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import { IconButton } from "@mui/material";
|
||||
import Paper from "@material-ui/core/Paper";
|
||||
import SearchIcon from "@material-ui/icons/Search";
|
||||
import InputBase from "@material-ui/core/InputBase";
|
||||
import Tabs from "@material-ui/core/Tabs";
|
||||
import Tab from "@material-ui/core/Tab";
|
||||
import Badge from "@material-ui/core/Badge";
|
||||
|
||||
import Tooltip from "@material-ui/core/Tooltip";
|
||||
|
||||
|
||||
import SearchIcon from "@material-ui/icons/Search";
|
||||
import MoveToInboxIcon from "@material-ui/icons/MoveToInbox";
|
||||
import CheckBoxIcon from "@material-ui/icons/CheckBox";
|
||||
import MenuIcon from "@material-ui/icons/Menu";
|
||||
import FindInPageIcon from '@material-ui/icons/FindInPage';
|
||||
|
||||
import FormControlLabel from "@material-ui/core/FormControlLabel";
|
||||
import Switch from "@material-ui/core/Switch";
|
||||
|
@ -63,6 +70,25 @@ const useStyles = makeStyles((theme) => ({
|
|||
},
|
||||
|
||||
serachInputWrapper: {
|
||||
flex: 1,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "10px",
|
||||
borderRadius: 40,
|
||||
padding: 4,
|
||||
marginRight: theme.spacing(1),
|
||||
},
|
||||
|
||||
searchInputHeader: {
|
||||
flex: 1,
|
||||
background: "#fff",
|
||||
display: "flex",
|
||||
borderRadius: 40,
|
||||
padding: 4,
|
||||
marginRight: theme.spacing(1),
|
||||
},
|
||||
|
||||
searchContentInput: {
|
||||
flex: 1,
|
||||
background: "#fff",
|
||||
display: "flex",
|
||||
|
@ -78,6 +104,11 @@ const useStyles = makeStyles((theme) => ({
|
|||
alignSelf: "center",
|
||||
},
|
||||
|
||||
menuSearch: {
|
||||
color: "grey",
|
||||
alignSelf: "center",
|
||||
},
|
||||
|
||||
searchInput: {
|
||||
flex: 1,
|
||||
border: "none",
|
||||
|
@ -95,20 +126,21 @@ const useStyles = makeStyles((theme) => ({
|
|||
},
|
||||
}));
|
||||
|
||||
const DEFAULT_SEARCH_PARAM = { searchParam: "", searchParamContent: "" }
|
||||
|
||||
const TicketsManager = () => {
|
||||
|
||||
const { tabOption, setTabOption } = useContext(TabTicketContext);
|
||||
|
||||
const {setSearchTicket} = useContext(SearchTicketContext)
|
||||
const { setSearchTicket } = useContext(SearchTicketContext)
|
||||
|
||||
const classes = useStyles();
|
||||
|
||||
const [searchParam, setSearchParam] = useState("");
|
||||
const [searchParam, setSearchParam] = useState(DEFAULT_SEARCH_PARAM);
|
||||
const [tab, setTab] = useState("open");
|
||||
const [tabOpen, setTabOpen] = useState("open");
|
||||
const [newTicketModalOpen, setNewTicketModalOpen] = useState(false);
|
||||
const [showAllTickets, setShowAllTickets] = useState(false);
|
||||
const searchInputRef = useRef();
|
||||
const { user } = useContext(AuthContext);
|
||||
|
||||
const [openCount, setOpenCount] = useState(0);
|
||||
|
@ -117,7 +149,16 @@ const TicketsManager = () => {
|
|||
const userQueueIds = user.queues.map((q) => q.id);
|
||||
const [selectedQueueIds, setSelectedQueueIds] = useState(userQueueIds || []);
|
||||
|
||||
const [showContentSearch, setShowContentSearch] = useState(false)
|
||||
const searchInputRef = useRef();
|
||||
const searchContentInputRef = useRef();
|
||||
const [inputSearch, setInputSearch] = useState('');
|
||||
const [inputContentSearch, setInputContentSearch] = useState("")
|
||||
|
||||
const [openTooltipSearch, setOpenTooltipSearch] = useState(false)
|
||||
|
||||
let searchTimeout;
|
||||
let searchContentTimeout;
|
||||
|
||||
useEffect(() => {
|
||||
if (user.profile.toUpperCase() === "ADMIN") {
|
||||
|
@ -135,22 +176,45 @@ const TicketsManager = () => {
|
|||
|
||||
}, [tab, setTabOption]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
// clearTimeout(searchContentTimeout);
|
||||
|
||||
// setSearchParam(prev => ({ ...prev, searchParamContent: "" }))
|
||||
|
||||
if (!inputContentSearch) return
|
||||
|
||||
if (!searchContentTimeout) return
|
||||
|
||||
// searchContentTimeout = setTimeout(() => {
|
||||
|
||||
// setSearchParam(prev => ({ ...prev, searchParamContent: inputContentSearch }));
|
||||
|
||||
// }, 500);
|
||||
|
||||
clearTimeout(searchContentTimeout);
|
||||
|
||||
setSearchParam(prev => ({ ...prev, searchParamContent: "" }))
|
||||
|
||||
|
||||
}, [inputContentSearch, searchContentTimeout]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
|
||||
if (tabOption === 'open') {
|
||||
|
||||
setTabOption('')
|
||||
setSearchParam('');
|
||||
setSearchParam(DEFAULT_SEARCH_PARAM);
|
||||
setInputSearch('');
|
||||
setInputContentSearch('')
|
||||
setTab("open");
|
||||
return;
|
||||
}
|
||||
|
||||
}, [tabOption, setTabOption])
|
||||
|
||||
let searchTimeout;
|
||||
|
||||
|
||||
const removeExtraSpace = (str) => {
|
||||
|
||||
str = str.replace(/^\s+/g, '')
|
||||
|
@ -163,24 +227,58 @@ const TicketsManager = () => {
|
|||
|
||||
setInputSearch(removeExtraSpace(searchedTerm))
|
||||
|
||||
setSearchTicket(searchParam)
|
||||
setSearchTicket(searchParam.searchParam)
|
||||
|
||||
clearTimeout(searchTimeout);
|
||||
|
||||
if (searchedTerm === "") {
|
||||
setSearchParam(searchedTerm);
|
||||
setSearchParam(prev => ({ ...prev, searchParam: searchedTerm }))
|
||||
setInputSearch(searchedTerm)
|
||||
setShowContentSearch(false)
|
||||
setTab("open");
|
||||
return;
|
||||
}
|
||||
|
||||
if (searchedTerm.length < 4) {
|
||||
setSearchParam(prev => ({ ...prev, searchParamContent: "" }))
|
||||
setInputContentSearch('')
|
||||
}
|
||||
|
||||
|
||||
searchTimeout = setTimeout(() => {
|
||||
|
||||
setSearchParam(searchedTerm);
|
||||
setSearchParam(prev => ({ ...prev, searchParam: searchedTerm }));
|
||||
|
||||
}, 500);
|
||||
};
|
||||
|
||||
const handleContentSearch = e => {
|
||||
|
||||
let searchedContentText = removeExtraSpace(e.target.value.toLowerCase())
|
||||
|
||||
setInputContentSearch(searchedContentText)
|
||||
|
||||
searchContentTimeout = setTimeout(() => {
|
||||
|
||||
setSearchParam(prev => ({ ...prev, searchParamContent: searchedContentText }));
|
||||
|
||||
}, 500);
|
||||
|
||||
}
|
||||
|
||||
const handleOpenTooltipSearch = () => {
|
||||
if (searchParam.searchParam.length < 4) {
|
||||
setOpenTooltipSearch(true)
|
||||
}
|
||||
}
|
||||
|
||||
const handleCloseTooltipSearch = () => {
|
||||
setOpenTooltipSearch(false)
|
||||
if (searchParam.searchParam.length < 4) {
|
||||
searchInputRef.current.focus()
|
||||
}
|
||||
}
|
||||
|
||||
const handleChangeTab = (e, newValue) => {
|
||||
setTab(newValue);
|
||||
};
|
||||
|
@ -233,15 +331,50 @@ const TicketsManager = () => {
|
|||
<Paper square elevation={0} className={classes.ticketOptionsBox}>
|
||||
{tab === "search" ? (
|
||||
<div className={classes.serachInputWrapper}>
|
||||
<SearchIcon className={classes.searchIcon} />
|
||||
<InputBase
|
||||
className={classes.searchInput}
|
||||
inputRef={searchInputRef}
|
||||
placeholder={i18n.t("tickets.search.placeholder")}
|
||||
type="search"
|
||||
value={inputSearch}
|
||||
onChange={handleSearch}
|
||||
/>
|
||||
<div className={classes.searchInputHeader}>
|
||||
<SearchIcon className={classes.searchIcon} />
|
||||
<InputBase
|
||||
className={classes.searchInput}
|
||||
inputRef={searchInputRef}
|
||||
placeholder={i18n.t("tickets.search.placeholder")}
|
||||
type="search"
|
||||
value={inputSearch}
|
||||
onChange={handleSearch}
|
||||
/>
|
||||
{/* <IconButton onClick={() => setShowContentSearch(prev => !prev)}>
|
||||
<MenuIcon className={classes.menuSearch} />
|
||||
</IconButton> */}
|
||||
<Tooltip
|
||||
open={openTooltipSearch}
|
||||
onOpen={() => handleOpenTooltipSearch()}
|
||||
onClose={() => handleCloseTooltipSearch()}
|
||||
title="Digite pelo menos 4 caracteres"
|
||||
arrow>
|
||||
<span>
|
||||
<IconButton
|
||||
disabled={searchParam.searchParam.length < 4}
|
||||
onClick={() => setShowContentSearch(prev => !prev)}
|
||||
>
|
||||
<MenuIcon className={classes.menuSearch} />
|
||||
</IconButton>
|
||||
</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
{
|
||||
// showContentSearch ?
|
||||
(showContentSearch && searchParam.searchParam.length >= 4) ?
|
||||
(<div className={classes.searchContentInput}>
|
||||
<FindInPageIcon className={classes.searchIcon} />
|
||||
<InputBase
|
||||
className={classes.searchInput}
|
||||
inputRef={searchContentInputRef}
|
||||
placeholder={i18n.t("Busca por conteúdo")}
|
||||
type="search"
|
||||
value={inputContentSearch}
|
||||
onChange={(e) => handleContentSearch(e)}
|
||||
/>
|
||||
</div>) : null
|
||||
}
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
|
@ -340,17 +473,18 @@ const TicketsManager = () => {
|
|||
</TabPanel>
|
||||
<TabPanel value={tab} name="search" className={classes.ticketsWrapper}>
|
||||
|
||||
|
||||
<TicketsList
|
||||
searchParam={searchParam}
|
||||
tab={tab}
|
||||
showAll={true}
|
||||
selectedQueueIds={selectedQueueIds}
|
||||
/>
|
||||
|
||||
|
||||
<TicketsList
|
||||
searchParam={searchParam.searchParam}
|
||||
searchParamContent={searchParam.searchParamContent}
|
||||
tab={tab}
|
||||
showAll={true}
|
||||
selectedQueueIds={selectedQueueIds}
|
||||
/>
|
||||
|
||||
</TabPanel>
|
||||
</Paper>
|
||||
);
|
||||
};
|
||||
|
||||
export default TicketsManager;
|
||||
export default TicketsManager;
|
|
@ -1,8 +1,7 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import React, { useState, useContext, useMemo } from "react";
|
||||
import { useHistory } from "react-router-dom";
|
||||
|
||||
import Button from "@material-ui/core/Button";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import Dialog from "@material-ui/core/Dialog";
|
||||
import Select from "@material-ui/core/Select";
|
||||
import FormControl from "@material-ui/core/FormControl";
|
||||
|
@ -13,102 +12,72 @@ import { makeStyles } from "@material-ui/core";
|
|||
import DialogActions from "@material-ui/core/DialogActions";
|
||||
import DialogContent from "@material-ui/core/DialogContent";
|
||||
import DialogTitle from "@material-ui/core/DialogTitle";
|
||||
import Autocomplete, {
|
||||
createFilterOptions,
|
||||
} from "@material-ui/lab/Autocomplete";
|
||||
import CircularProgress from "@material-ui/core/CircularProgress";
|
||||
|
||||
import { i18n } from "../../translate/i18n";
|
||||
import api from "../../services/api";
|
||||
import ButtonWithSpinner from "../ButtonWithSpinner";
|
||||
import toastError from "../../errors/toastError";
|
||||
import useQueues from "../../hooks/useQueues";
|
||||
|
||||
import { WhatsAppsContext } from "../../context/WhatsApp/WhatsAppsContext";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
maxWidth: {
|
||||
width: "100%",
|
||||
},
|
||||
maxWidth: {
|
||||
width: "100%",
|
||||
},
|
||||
}));
|
||||
|
||||
const filterOptions = createFilterOptions({
|
||||
trim: true,
|
||||
});
|
||||
// Receive array of queues arrays
|
||||
// Return a new array with unique queues from all arrays has passed by the parameter
|
||||
const queueArraysToOneArray = (array) => {
|
||||
if (!array) return []
|
||||
const map = {}
|
||||
const uniqueQueuesAvailable = []
|
||||
array.forEach((queues) => {
|
||||
queues.forEach(({ id, name, color }) => {
|
||||
if (!map[id]) {
|
||||
map[id] = true
|
||||
uniqueQueuesAvailable.push({ id, name, color })
|
||||
}
|
||||
})
|
||||
})
|
||||
return uniqueQueuesAvailable
|
||||
}
|
||||
|
||||
|
||||
const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => {
|
||||
const history = useHistory();
|
||||
const [options, setOptions] = useState([]);
|
||||
const [queues, setQueues] = useState([]);
|
||||
const [allQueues, setAllQueues] = useState([]);
|
||||
const { whatsApps } = useContext(WhatsAppsContext);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [searchParam, setSearchParam] = useState("");
|
||||
const [selectedUser, setSelectedUser] = useState(null);
|
||||
const [selectedQueue, setSelectedQueue] = useState('');
|
||||
const classes = useStyles();
|
||||
const { findAll: findAllQueues } = useQueues();
|
||||
|
||||
useEffect(() => {
|
||||
const loadQueues = async () => {
|
||||
const list = await findAllQueues();
|
||||
setAllQueues(list);
|
||||
setQueues(list);
|
||||
}
|
||||
loadQueues();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!modalOpen || searchParam.length < 3) {
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
const delayDebounceFn = setTimeout(() => {
|
||||
const fetchUsers = async () => {
|
||||
try {
|
||||
const { data } = await api.get("/users/", {
|
||||
params: { searchParam },
|
||||
});
|
||||
setOptions(data.users);
|
||||
setLoading(false);
|
||||
} catch (err) {
|
||||
setLoading(false);
|
||||
toastError(err);
|
||||
}
|
||||
};
|
||||
|
||||
fetchUsers();
|
||||
}, 500);
|
||||
return () => clearTimeout(delayDebounceFn);
|
||||
}, [searchParam, modalOpen]);
|
||||
const queues = useMemo(() => {
|
||||
if (!whatsApps) return []
|
||||
const whatsAppsQueues = whatsApps.map(({ queues }) => queues)
|
||||
//const whatsAppsQueues = whatsApps.filter(({ status }) => status === "CONNECTED" ).map(({ queues }) => queues)
|
||||
const uniqueQueuesAvailable = queueArraysToOneArray(whatsAppsQueues)
|
||||
return uniqueQueuesAvailable
|
||||
}, [whatsApps])
|
||||
const [itemHover, setItemHover] = useState(-1)
|
||||
|
||||
const handleClose = () => {
|
||||
onClose();
|
||||
setSearchParam("");
|
||||
setSelectedUser(null);
|
||||
};
|
||||
|
||||
const handleSaveTicket = async e => {
|
||||
e.preventDefault();
|
||||
if (!ticketid) return;
|
||||
if (!selectedQueue) return;
|
||||
setLoading(true);
|
||||
try {
|
||||
let data = {};
|
||||
|
||||
if (selectedUser) {
|
||||
data.userId = selectedUser.id
|
||||
}
|
||||
|
||||
if (selectedQueue && selectedQueue !== null) {
|
||||
data.queueId = selectedQueue
|
||||
|
||||
if (!selectedUser) {
|
||||
data.status = 'pending';
|
||||
data.userId = null;
|
||||
}
|
||||
}
|
||||
|
||||
// test del PARA APARECER NA FILA DE OUTRO ATENDENTE E O MESMO CLICAR EM ACEITAR AO INVES DE ENVIAR PARA ATENDENDO
|
||||
data.status = 'pending'
|
||||
data.transfer = true
|
||||
|
||||
await api.put(`/tickets/${ticketid}`, data);
|
||||
|
||||
|
@ -127,56 +96,26 @@ const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => {
|
|||
{i18n.t("transferTicketModal.title")}
|
||||
</DialogTitle>
|
||||
<DialogContent dividers>
|
||||
<Autocomplete
|
||||
style={{ width: 300, marginBottom: 20 }}
|
||||
getOptionLabel={option => `${option.name}`}
|
||||
onChange={(e, newValue) => {
|
||||
setSelectedUser(newValue);
|
||||
if (newValue != null && Array.isArray(newValue.queues)) {
|
||||
setQueues(newValue.queues);
|
||||
} else {
|
||||
setQueues(allQueues);
|
||||
setSelectedQueue('');
|
||||
}
|
||||
}}
|
||||
options={options}
|
||||
filterOptions={filterOptions}
|
||||
freeSolo
|
||||
autoHighlight
|
||||
noOptionsText={i18n.t("transferTicketModal.noOptions")}
|
||||
loading={loading}
|
||||
renderInput={params => (
|
||||
<TextField
|
||||
{...params}
|
||||
label={i18n.t("transferTicketModal.fieldLabel")}
|
||||
variant="outlined"
|
||||
required
|
||||
autoFocus
|
||||
onChange={e => setSearchParam(e.target.value)}
|
||||
InputProps={{
|
||||
...params.InputProps,
|
||||
endAdornment: (
|
||||
<React.Fragment>
|
||||
{loading ? (
|
||||
<CircularProgress color="inherit" size={20} />
|
||||
) : null}
|
||||
{params.InputProps.endAdornment}
|
||||
</React.Fragment>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<FormControl variant="outlined" className={classes.maxWidth}>
|
||||
<InputLabel>{i18n.t("transferTicketModal.fieldQueueLabel")}</InputLabel>
|
||||
<Select
|
||||
value={selectedQueue}
|
||||
onChange={(e) => setSelectedQueue(e.target.value)}
|
||||
label={i18n.t("transferTicketModal.fieldQueuePlaceholder")}
|
||||
required
|
||||
>
|
||||
<MenuItem value={''}> </MenuItem>
|
||||
<MenuItem style={{ background: "white", }} value={''}> </MenuItem>
|
||||
{queues.map((queue) => (
|
||||
<MenuItem key={queue.id} value={queue.id}>{queue.name}</MenuItem>
|
||||
<MenuItem
|
||||
key={queue.id}
|
||||
value={queue.id}
|
||||
onMouseEnter={() => setItemHover(queue.id)}
|
||||
onMouseLeave={() => setItemHover(-1)}
|
||||
style={{
|
||||
background: queue.id !== itemHover ? "white" : queue.color,
|
||||
}}
|
||||
>{queue.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
@ -200,8 +139,8 @@ const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => {
|
|||
</ButtonWithSpinner>
|
||||
</DialogActions>
|
||||
</form>
|
||||
</Dialog>
|
||||
</Dialog >
|
||||
);
|
||||
};
|
||||
|
||||
export default TransferTicketModal;
|
||||
export default TransferTicketModal;
|
|
@ -5,6 +5,7 @@ import api from "../../services/api";
|
|||
|
||||
const useTickets = ({
|
||||
searchParam,
|
||||
searchParamContent,
|
||||
pageNumber,
|
||||
status,
|
||||
date,
|
||||
|
@ -35,6 +36,7 @@ const useTickets = ({
|
|||
const { data } = await api.get("/tickets", {
|
||||
params: {
|
||||
searchParam,
|
||||
searchParamContent,
|
||||
pageNumber,
|
||||
status,
|
||||
date,
|
||||
|
@ -63,6 +65,7 @@ const useTickets = ({
|
|||
return () => clearTimeout(delayDebounceFn);
|
||||
}, [
|
||||
searchParam,
|
||||
searchParamContent,
|
||||
pageNumber,
|
||||
status,
|
||||
date,
|
||||
|
|
|
@ -37,8 +37,9 @@ import { Can } from "../../components/Can";
|
|||
|
||||
import apiBroker from "../../services/apiBroker";
|
||||
import fileDownload from 'js-file-download'
|
||||
import ContactCreateTicketModal from "../../components/ContactCreateTicketModal";
|
||||
|
||||
|
||||
|
||||
|
||||
const reducer = (state, action) => {
|
||||
|
||||
|
@ -111,6 +112,7 @@ const Contacts = () => {
|
|||
const [contacts, dispatch] = useReducer(reducer, []);
|
||||
const [selectedContactId, setSelectedContactId] = useState(null);
|
||||
const [contactModalOpen, setContactModalOpen] = useState(false);
|
||||
const [isCreateTicketModalOpen, setIsCreateTicketModalOpen] = useState(false)
|
||||
const [deletingContact, setDeletingContact] = useState(null);
|
||||
const [confirmOpen, setConfirmOpen] = useState(false);
|
||||
const [hasMore, setHasMore] = useState(false);
|
||||
|
@ -118,17 +120,17 @@ const Contacts = () => {
|
|||
|
||||
const [onQueueStatus, setOnQueueProcessStatus] = useState(undefined)
|
||||
|
||||
const [zipfile, setZipFile] = useState()
|
||||
|
||||
const [zipfile, setZipFile] = useState()
|
||||
|
||||
|
||||
async function handleChange(event) {
|
||||
|
||||
try {
|
||||
|
||||
if (event.target.files[0].size > 1024 * 1024 * 4){
|
||||
if (event.target.files[0].size > 1024 * 1024 * 4) {
|
||||
alert('Arquivo não pode ser maior que 4 MB!')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("adminId", user.id);
|
||||
|
@ -302,21 +304,30 @@ const Contacts = () => {
|
|||
setContactModalOpen(false);
|
||||
};
|
||||
|
||||
const handleSaveTicket = async (contactId) => {
|
||||
if (!contactId) return;
|
||||
setLoading(true);
|
||||
try {
|
||||
const { data: ticket } = await api.post("/tickets", {
|
||||
contactId: contactId,
|
||||
userId: user?.id,
|
||||
status: "open",
|
||||
});
|
||||
history.push(`/tickets/${ticket.id}`);
|
||||
} catch (err) {
|
||||
toastError(err);
|
||||
}
|
||||
setLoading(false);
|
||||
};
|
||||
const handleOpenCreateTicketModal = (contactId) => {
|
||||
setSelectedContactId(contactId)
|
||||
setIsCreateTicketModalOpen(true)
|
||||
}
|
||||
|
||||
const handleCloseCreateTicketModal = () => {
|
||||
setIsCreateTicketModalOpen(false)
|
||||
}
|
||||
|
||||
// const handleSaveTicket = async (contactId) => {
|
||||
// if (!contactId) return;
|
||||
// setLoading(true);
|
||||
// try {
|
||||
// const { data: ticket } = await api.post("/tickets", {
|
||||
// contactId: contactId,
|
||||
// userId: user?.id,
|
||||
// status: "open",
|
||||
// });
|
||||
// history.push(`/tickets/${ticket.id}`);
|
||||
// } catch (err) {
|
||||
// toastError(err);
|
||||
// }
|
||||
// setLoading(false);
|
||||
// };
|
||||
|
||||
const hadleEditContact = (contactId) => {
|
||||
setSelectedContactId(contactId);
|
||||
|
@ -415,21 +426,21 @@ const Contacts = () => {
|
|||
switch (param) {
|
||||
case 'empty':
|
||||
return (
|
||||
<>
|
||||
<>
|
||||
|
||||
<input
|
||||
type="file"
|
||||
accept=".csv"
|
||||
style={{ display: 'none' }}
|
||||
onChange={handleChange}
|
||||
id="contained-button-file"
|
||||
/>
|
||||
<input
|
||||
type="file"
|
||||
accept=".csv"
|
||||
style={{ display: 'none' }}
|
||||
onChange={handleChange}
|
||||
id="contained-button-file"
|
||||
/>
|
||||
|
||||
<label htmlFor="contained-button-file">
|
||||
<Button variant="contained" color="primary" component="span">
|
||||
CSV UPLOAD
|
||||
</Button>
|
||||
</label>
|
||||
<label htmlFor="contained-button-file">
|
||||
<Button variant="contained" color="primary" component="span">
|
||||
CSV UPLOAD
|
||||
</Button>
|
||||
</label>
|
||||
|
||||
{/* <Button
|
||||
disabled={query && query.length > 0 ? false : true}
|
||||
|
@ -495,6 +506,11 @@ const Contacts = () => {
|
|||
aria-labelledby="form-dialog-title"
|
||||
contactId={selectedContactId}
|
||||
></ContactModal>
|
||||
<ContactCreateTicketModal
|
||||
modalOpen={isCreateTicketModalOpen}
|
||||
onClose={handleCloseCreateTicketModal}
|
||||
contactId={selectedContactId}
|
||||
/>
|
||||
<ConfirmationModal
|
||||
title={
|
||||
deletingContact
|
||||
|
@ -609,7 +625,7 @@ const Contacts = () => {
|
|||
<TableCell align="center">
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={() => handleSaveTicket(contact.id)}
|
||||
onClick={() => handleOpenCreateTicketModal(contact.id)}
|
||||
>
|
||||
<WhatsAppIcon />
|
||||
</IconButton>
|
||||
|
@ -646,4 +662,4 @@ const Contacts = () => {
|
|||
);
|
||||
};
|
||||
|
||||
export default Contacts;
|
||||
export default Contacts;
|
|
@ -16,7 +16,7 @@ const useLoadData = (setLoading, dispatch, route, dispatchType) => {
|
|||
setLoading(false);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
}, [setLoading, dispatch, route, dispatchType]);
|
||||
}
|
||||
|
||||
export default useLoadData;
|
|
@ -18,7 +18,7 @@ const useSocket = (dispatch, socketEvent, typeUpdate, typeDelete, payloadUpdate,
|
|||
return () => {
|
||||
socket.disconnect();
|
||||
};
|
||||
}, []);
|
||||
}, [dispatch, socketEvent, typeUpdate, typeDelete, payloadUpdate, payloadDelete]);
|
||||
}
|
||||
|
||||
export default useSocket;
|
Loading…
Reference in New Issue