Compare commits

..

No commits in common. "0048fa483fb31b9432be58bbff0d8e248cc65a1c" and "6450fb6ea74ff2a591367586f7561e46331194d6" have entirely different histories.

65 changed files with 701 additions and 1297 deletions

View File

@ -885,15 +885,11 @@ async function handleMessage(msg) {
if (msg.fromMe) { if (msg.fromMe) {
console.log('MSG FROM ME')
msgContact = await client.getContactById(msg.to) msgContact = await client.getContactById(msg.to)
} }
else { else {
console.log('MSG FROM CLIENT')
console.log('################# RECEIVING MESSAGE FROM: ', msg.from, ' to ', msg.to) console.log('################# RECEIVING MESSAGE FROM: ', msg.from, ' to ', msg.to)
msgContact = await msg.getContact() msgContact = await msg.getContact()
@ -916,10 +912,10 @@ async function handleMessage(msg) {
msgContact: msgContact, msgContact: msgContact,
chat: chat, chat: chat,
quotedMsg: quotedMsg ? quotedMsg.id.id : null, quotedMsg: quotedMsg ? quotedMsg.id.id : null,
media: media, media: media
getContactById: msg.fromMe ? await client.getContactById(msg.to) : await client.getContactById(msg.from)
} }
socketIo.emit("message_create", data) socketIo.emit("message_create", data)
} }

View File

@ -17,7 +17,6 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@sentry/node": "^5.29.2", "@sentry/node": "^5.29.2",
"@socket.io/redis-adapter": "^7.2.0",
"@types/fluent-ffmpeg": "^2.1.21", "@types/fluent-ffmpeg": "^2.1.21",
"@types/pino": "^6.3.4", "@types/pino": "^6.3.4",
"axios": "^1.2.3", "axios": "^1.2.3",
@ -42,13 +41,12 @@
"pino": "^6.9.0", "pino": "^6.9.0",
"pino-pretty": "^9.1.1", "pino-pretty": "^9.1.1",
"qrcode-terminal": "^0.12.0", "qrcode-terminal": "^0.12.0",
"redis": "^4.6.13",
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",
"sequelize": "^5.22.3", "sequelize": "^5.22.3",
"sequelize-cli": "^5.5.1", "sequelize-cli": "^5.5.1",
"sequelize-typescript": "^1.1.0", "sequelize-typescript": "^1.1.0",
"sharp": "^0.32.5", "sharp": "^0.32.5",
"socket.io": "^4.7.5", "socket.io": "^3.0.5",
"socket.io-client": "^4.5.4", "socket.io-client": "^4.5.4",
"uuid": "^8.3.2", "uuid": "^8.3.2",
"whatsapp-web.js": "github:pedroslopez/whatsapp-web.js", "whatsapp-web.js": "github:pedroslopez/whatsapp-web.js",
@ -56,7 +54,6 @@
"yup": "^0.32.8" "yup": "^0.32.8"
}, },
"devDependencies": { "devDependencies": {
"@types/lodash": "4.14",
"@types/bcryptjs": "^2.4.2", "@types/bcryptjs": "^2.4.2",
"@types/bluebird": "^3.5.32", "@types/bluebird": "^3.5.32",
"@types/cookie-parser": "^1.4.2", "@types/cookie-parser": "^1.4.2",

View File

@ -1,4 +1,5 @@
import { Request, Response } from "express"; import { Request, Response } from "express";
import whatsappOfficialAPI from "../helpers/WhatsappOfficialAPI";
import SetTicketMessagesAsRead from "../helpers/SetTicketMessagesAsRead"; import SetTicketMessagesAsRead from "../helpers/SetTicketMessagesAsRead";
import { getIO } from "../libs/socket"; import { getIO } from "../libs/socket";
@ -21,7 +22,6 @@ import Whatsapp from "../models/Whatsapp";
import checkLastClientMsg24hs from "../helpers/CheckLastClientMsg24hs"; import checkLastClientMsg24hs from "../helpers/CheckLastClientMsg24hs";
import AppError from "../errors/AppError"; import AppError from "../errors/AppError";
import { get } from "../helpers/RedisClient"; import { get } from "../helpers/RedisClient";
import createApiClientWhatsOfficial from "../helpers/WhatsappOfficialAPI";
type IndexQuery = { type IndexQuery = {
pageNumber: string; pageNumber: string;
@ -123,12 +123,7 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
} }
} else { } else {
try { try {
const { wabaId, whatsappOfficialToken }: any = const { wabaId }: any = await Whatsapp.findByPk(whatsappId);
await Whatsapp.findByPk(whatsappId);
const whatsappOfficialAPI = createApiClientWhatsOfficial(
whatsappOfficialToken
);
const { data } = await whatsappOfficialAPI.get( const { data } = await whatsappOfficialAPI.get(
`/${process.env.VERSION}/${wabaId}/message_templates?language=pt_BR` `/${process.env.VERSION}/${wabaId}/message_templates?language=pt_BR`

View File

@ -36,15 +36,13 @@ import ShowUserService from "../services/UserServices/ShowUserService";
import fs from "fs"; import fs from "fs";
import receiveWhatsAppMediaOfficialAPI from "../helpers/ReceiveWhatsAppMediaOfficialAPI"; import receiveWhatsAppMediaOfficialAPI from "../helpers/ReceiveWhatsAppMediaOfficialAPI";
import whatsappOfficialAPI from "../helpers/WhatsappOfficialAPI";
import whatsappOfficialNumberInfo from "../helpers/WhatsappOfficialNumberInfo"; import whatsappOfficialNumberInfo from "../helpers/WhatsappOfficialNumberInfo";
import { getSettingValue } from "../helpers/WhaticketSettings"; import { getSettingValue } from "../helpers/WhaticketSettings";
import ListWhatsAppsNumber from "../services/WhatsappService/ListWhatsAppsNumber"; import ListWhatsAppsNumber from "../services/WhatsappService/ListWhatsAppsNumber";
import SettingTicket from "../models/SettingTicket"; import SettingTicket from "../models/SettingTicket";
import { Op } from "sequelize"; import { Op } from "sequelize";
import { del, get, getKeysByPattern, set, setCBPWhatsappOfficial } from "../helpers/RedisClient"; import { del, get, set } from "../helpers/RedisClient";
import axios from "axios";
interface WhatsappData { interface WhatsappData {
name: string; name: string;
@ -217,48 +215,6 @@ export const weebhook = async (
return res.sendStatus(500); return res.sendStatus(500);
} }
if(
req?.body?.entry?.length > 0 &&
req?.body?.entry[0]?.changes?.length > 0 &&
req?.body?.entry[0]?.changes?.length > 0 &&
req?.body?.entry[0]?.changes[0]?.value?.statuses?.length>0 &&
req?.body?.entry[0]?.changes[0]?.value?.statuses[0]?.recipient_id &&
req?.body?.entry[0]?.changes[0]?.value?.statuses[0]?.conversation?.origin?.type){
const company_phone = req?.body?.entry[0]?.changes[0]?.value?.metadata?.display_phone_number
const client_phone = req?.body?.entry[0]?.changes[0]?.value?.statuses[0]?.recipient_id
const conversation_type = req?.body?.entry[0]?.changes[0]?.value?.statuses[0].conversation.origin.type
const billable = req?.body?.entry[0]?.changes[0]?.value?.statuses[0].pricing.billable
const pricing_model = req?.body?.entry[0]?.changes[0]?.value?.statuses[0].pricing.pricing_model
const conversation_type_category = req?.body?.entry[0]?.changes[0]?.value?.statuses[0].pricing.category
const msg_id = req?.body?.entry[0]?.changes[0]?.value?.statuses[0].id
const _contact_to_exist = await get({
key: "whatsapp:*",
value: `${company_phone}`
});
if(_contact_to_exist){
const lst_services_cbp = await getKeysByPattern(company_phone, client_phone, conversation_type_category)
if(lst_services_cbp && lst_services_cbp.length > 0){
for(const item of lst_services_cbp){
if(!item.split(':').includes(conversation_type_category)){
await setCBP(msg_id, company_phone, client_phone, conversation_type_category, billable, pricing_model)
}
}
}else{
await setCBP(msg_id, company_phone, client_phone, conversation_type_category, billable, pricing_model)
}
console.log('_contact_to_exist: ', _contact_to_exist)
}
}
// MESSAGE // MESSAGE
if (req.body.object) { if (req.body.object) {
if ( if (
@ -332,8 +288,7 @@ export const weebhook = async (
let filename = await receiveWhatsAppMediaOfficialAPI( let filename = await receiveWhatsAppMediaOfficialAPI(
mediaId, mediaId,
whatsapp.phoneNumberId, whatsapp.phoneNumberId
whatsapp.whatsappOfficialToken
); );
if (!filename) throw new AppError("There was an error"); if (!filename) throw new AppError("There was an error");
@ -422,11 +377,9 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
} else if (!isOfficial) { } else if (!isOfficial) {
phoneNumberId = ""; phoneNumberId = "";
wabaId = ""; wabaId = "";
//number = ""; number = "";
}
if(!number){
number = getNumberFromName(name)
} }
let invalidPhoneName = validatePhoneName(name); let invalidPhoneName = validatePhoneName(name);
if (invalidPhoneName) { if (invalidPhoneName) {
@ -526,11 +479,9 @@ export const update = async (
} else if (!isOfficial) { } else if (!isOfficial) {
whatsappData.phoneNumberId = ""; whatsappData.phoneNumberId = "";
whatsappData.wabaId = ""; whatsappData.wabaId = "";
//whatsappData.number = ""; whatsappData.number = "";
}
if(!whatsappData?.number){
whatsappData.number = getNumberFromName(whatsappData.name)
} }
const { whatsapp, oldDefaultWhatsapp } = await UpdateWhatsAppService({ const { whatsapp, oldDefaultWhatsapp } = await UpdateWhatsAppService({
whatsappData, whatsappData,
whatsappId whatsappId
@ -675,56 +626,3 @@ const checkWhatsAppData = ({
return { message: "urlApi is required!" }; return { message: "urlApi is required!" };
} }
}; };
async function setCBP(msg_id: any, company_phone: any, client_phone: any, conversation_type_category: any, billable:string, pricing_model:string) {
const message = await Message.findByPk(msg_id)
if (message) {
await setCBPWhatsappOfficial(company_phone, client_phone, conversation_type_category, msg_id, `${message.ticketId}`)
await sendToAPIUsage(msg_id,
company_phone,
client_phone,
conversation_type_category,
`${message.ticketId}`,
billable,
pricing_model
)
}
}
async function sendToAPIUsage(msg_id: any, company_phone: any, client_phone: any, conversation_type_category: any, ticketId: any, billable:string, pricing_model:string) {
const data = JSON.stringify({
"companyId": process.env.COMPANY_ID || company_phone,
"companyPhone": company_phone,
"clientPhone": client_phone,
"provider": "meta",
"product": "whatsapp",
"type": conversation_type_category,
"msgId": msg_id,
"ticketId": `${ticketId}`,
"ticketUrl": `${process.env.FRONTEND_URL}/tickets/${ticketId}`,
"billable": billable,
"pricing_model": pricing_model
});
const config = {
method: 'post',
url: 'http://172.31.187.24:6008/api/v1/billing/usage-whatsapp',
headers: {
'Authorization': 'Bearer 2ivck10D3o9qAZi0pkKudVDl9bdEVXY2s8gdxZ0jYgL1DZWTgDz6wDiIjlWgYmJtVOoqf0b42ZTLBRrfo8WoAaScRsujz3jQUNXdchSg0o43YilZGmVhheGJNAeIQRknHEll4nRJ7avcFgmDGoYbEey7TSC8EHS4Z3gzeufYYSfnKNDBwwzBURIQrTOxYFe3tBHsGOzwnuD2lU5tnEx7tr2XRO4zRNYeNY4lMBOFM0mRuyAe4kuqTrKXmJ8As200',
'Content-Type': 'application/json'
},
data: data
};
try {
const response = await axios(config);
console.log('Response from whatsapp api usage: ',JSON.stringify(response.data));
} catch (error) {
console.log('Error on try register the whatsapp usage: ', error);
}
}

View File

@ -1,14 +0,0 @@
import { QueryInterface, DataTypes } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.addColumn("Users", "identifier", {
type: DataTypes.STRING,
allowNull: true
});
},
down: (queryInterface: QueryInterface) => {
return queryInterface.removeColumn("Users", "identifier");
}
};

View File

@ -1,14 +0,0 @@
import { QueryInterface, DataTypes } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.addColumn("Whatsapps", "whatsappOfficialToken", {
type: DataTypes.STRING,
allowNull: true
});
},
down: (queryInterface: QueryInterface) => {
return queryInterface.removeColumn("Whatsapps", "whatsappOfficialToken");
}
};

View File

@ -10,6 +10,7 @@ import {
import { writeFile } from "fs"; import { writeFile } from "fs";
import whatsappOfficialAPI from "./WhatsappOfficialAPI";
import path, { join } from "path"; import path, { join } from "path";
import { promisify } from "util"; import { promisify } from "util";
@ -17,20 +18,14 @@ import mime from "mime";
import fs from "fs"; import fs from "fs";
import { response } from "express"; import { response } from "express";
import createApiClientWhatsOfficial from "./WhatsappOfficialAPI";
const writeFileAsync = promisify(writeFile); const writeFileAsync = promisify(writeFile);
async function receiveWhatsAppMediaOfficialAPI( async function receiveWhatsAppMediaOfficialAPI(
mediaId: string, mediaId: string,
phoneNumberId: string, phoneNumberId: string
whatsappOfficialToken: string
) { ) {
try { try {
const whatsappOfficialAPI = createApiClientWhatsOfficial(
whatsappOfficialToken
);
const { data } = await whatsappOfficialAPI.get( const { data } = await whatsappOfficialAPI.get(
`/${process.env.VERSION}/${mediaId}?phone_number_id=${phoneNumberId}` `/${process.env.VERSION}/${mediaId}?phone_number_id=${phoneNumberId}`
); );
@ -38,7 +33,7 @@ async function receiveWhatsAppMediaOfficialAPI(
if (data && data?.url) { if (data && data?.url) {
const config: any = { const config: any = {
headers: { headers: {
Authorization: `Bearer ${whatsappOfficialToken}` Authorization: `Bearer ${process.env.TOKEN}`
}, },
responseType: "arraybuffer" responseType: "arraybuffer"
}; };

View File

@ -158,46 +158,6 @@ export async function findObject(
return result; return result;
} }
export async function setCBPWhatsappOfficial(
company_phone:string,
client_phone:string,
conversation_type:string,
msg_id: string,
ticketId?: string
) {
const key = `company_phone:${company_phone}:client_phone:${client_phone}:conversation_type:${conversation_type}`;
const result = await redis.hmset(
key,
"company_phone",
company_phone,
"client_phone",
client_phone,
"conversation_type",
conversation_type,
"msg_id",
msg_id,
"ticketId",
ticketId
);
await redis.expire(key, 86400);
}
export async function getKeysByPattern(company_phone:string, client_phone:string, conversation_type:string,) {
const pattern = `company_phone:${company_phone}:client_phone:${client_phone}:conversation_type:${conversation_type}*`;
const keys = [];
let cursor = "0";
do {
const result = await redis.scan(cursor, "MATCH", pattern, "COUNT", 100);
cursor = result[0];
keys.push(...result[1]);
} while (cursor !== "0");
return keys;
}
export async function deleteObject( export async function deleteObject(
whatsappId: string, whatsappId: string,
contactId: string, contactId: string,

View File

@ -104,16 +104,16 @@ const monitor = async () => {
stdout = stdout[1].trim().split(/\s+/); stdout = stdout[1].trim().split(/\s+/);
// DISK SPACE MONITORING // DISK SPACE MONITORING
// const io = getIO(); const io = getIO();
// io.emit("diskSpaceMonit", { io.emit("diskSpaceMonit", {
// action: "update", action: "update",
// diskSpace: { diskSpace: {
// size: stdout[1], size: stdout[1],
// used: stdout[2], used: stdout[2],
// available: stdout[3], available: stdout[3],
// use: stdout[4] use: stdout[4]
// } }
// }); });
let data: any = {}; let data: any = {};

View File

@ -5,6 +5,8 @@ import Ticket from "../models/Ticket";
import Whatsapp from "../models/Whatsapp"; import Whatsapp from "../models/Whatsapp";
import endPointQuery from "./old_EndPointQuery"; import endPointQuery from "./old_EndPointQuery";
import whatsappOfficialAPI from "./WhatsappOfficialAPI";
export async function setMessageAsRead(ticket: Ticket) { export async function setMessageAsRead(ticket: Ticket) {
if (ticket?.phoneNumberId) { if (ticket?.phoneNumberId) {
return; return;

View File

@ -3,28 +3,14 @@ import https from "https"
import http from "http" import http from "http"
// const api = axios.create({ const api = axios.create({
// baseURL: process.env.URL_WHATSAPP_API, baseURL: process.env.URL_WHATSAPP_API,
// headers: { headers: {
// Accept: "application/json", Accept: "application/json",
// Authorization: `Bearer ${process.env.TOKEN}` Authorization: `Bearer ${process.env.TOKEN}`
// }, },
// httpAgent: new http.Agent({ keepAlive: true }), httpAgent: new http.Agent({ keepAlive: true }),
// httpsAgent: new https.Agent({ keepAlive: true }) httpsAgent: new https.Agent({ keepAlive: true })
// }); });
// export default api; export default api;
const createApiClientWhatsOfficial = (token: string) => {
return axios.create({
baseURL: process.env.URL_WHATSAPP_API,
headers: {
Accept: "application/json",
Authorization: `Bearer ${token}`
},
httpAgent: new http.Agent({ keepAlive: true }),
httpsAgent: new https.Agent({ keepAlive: true })
});
};
export default createApiClientWhatsOfficial;

View File

@ -1,15 +1,7 @@
import Whatsapp from "../models/Whatsapp"; import whatsappOfficialAPI from "./WhatsappOfficialAPI";
import createApiClientWhatsOfficial from "./WhatsappOfficialAPI";
async function whatsappOfficialNumberInfo(wabaId: string) { async function whatsappOfficialNumberInfo(wabaId: string) {
try { try {
const { whatsappOfficialToken }: any = await Whatsapp.findOne({
where: { wabaId }
});
const whatsappOfficialAPI = createApiClientWhatsOfficial(
whatsappOfficialToken
);
const { data } = await whatsappOfficialAPI.get( const { data } = await whatsappOfficialAPI.get(
`/${process.env.VERSION}/${wabaId}/phone_numbers` `/${process.env.VERSION}/${wabaId}/phone_numbers`
); );

View File

@ -1,9 +1,4 @@
import { values } from "sequelize/types/lib/operators";
import Ticket from "../models/Ticket";
import { get, set } from "./RedisClient"; import { get, set } from "./RedisClient";
import { getIO } from "../libs/socket";
import UpdateTicketService from "../services/TicketServices/UpdateTicketService";
import { v4 as uuidv4 } from "uuid";
async function controllByNumber() { async function controllByNumber() {
let tickets = await get({ key: "remote:ticketId*", parse: false }); let tickets = await get({ key: "remote:ticketId*", parse: false });
@ -13,46 +8,30 @@ async function controllByNumber() {
let controll: any[] = []; let controll: any[] = [];
for (const ticket of tickets) { for (const ticket of tickets) {
let match = ticket?.match(/"whatsappId":(\d+)/); let match = ticket.match(/"whatsappId":(\d+)/);
let whatsappId = match ? match[1] : null; let whatsappId = match ? match[1] : null;
const whatsapp = await get({ const whatsapp = await get({
key: `whatsapp:${whatsappId}` key: `whatsapp:${whatsappId}`
}); });
match = whatsapp?.match(/"number":"(\d+)"/); match = whatsapp.match(/"number":"(\d+)"/);
let number = match ? match[1] : null; let number = match ? match[1] : null;
match = ticket?.match(/"id":(\d+)/); match = ticket.match(/"id":(\d+)/);
let ticketId = match ? match[1] : null; let ticketId = match ? match[1] : null;
number = JSON.parse(number); number = JSON.parse(number);
ticketId = JSON.parse(ticketId); ticketId = JSON.parse(ticketId);
const index = controll?.findIndex((c: any) => c.number == number); const index = controll.findIndex((c: any) => c.number == number);
if (index == -1) { if (index == -1) {
controll?.push({ ticketId, number }); controll.push({ ticketId, number });
} }
} }
const ticketIds = controll?.map((c: any) => c.ticketId); const ticketIds = controll.map((c: any) => c.ticketId);
//console.log("=======> ticketIds: ", ticketIds);
for (const ticketId of ticketIds) {
const ticket: any = await Ticket.findByPk(ticketId);
if(ticket){
const { status } = ticket;
if (status && status == "pending") {
await UpdateTicketService({
ticketData: { statusChatEnd: uuidv4() },
ticketId: ticket.id
});
}
}
}
set(`remote:controll`, JSON.stringify(ticketIds)); set(`remote:controll`, JSON.stringify(ticketIds));

View File

@ -1,4 +1,3 @@
import { where } from "sequelize";
import { getIO } from "../libs/socket"; import { getIO } from "../libs/socket";
import Contact from "../models/Contact"; import Contact from "../models/Contact";
import Ticket from "../models/Ticket"; import Ticket from "../models/Ticket";
@ -6,9 +5,8 @@ import {
isValidMsg, isValidMsg,
verifyMessage verifyMessage
} from "../services/WbotServices/wbotMessageListener"; } from "../services/WbotServices/wbotMessageListener";
import { get } from "./RedisClient";
import createApiClientWhatsOfficial from "./WhatsappOfficialAPI"; import whatsappOfficialAPI from "./WhatsappOfficialAPI";
import Whatsapp from "../models/Whatsapp";
async function sendWhatsAppMessageOfficialAPI( async function sendWhatsAppMessageOfficialAPI(
ticket: Ticket, ticket: Ticket,
@ -54,14 +52,7 @@ async function sendWhatsAppMessageOfficialAPI(
return; return;
} }
const { whatsappOfficialToken }: any = await Whatsapp.findOne({ console.log("SEND MESSAGE: ", JSON.stringify(data, null,2));
where: { phoneNumberId }
});
console.log("SEND MESSAGE: ", JSON.stringify(data, null, 2));
const whatsappOfficialAPI = createApiClientWhatsOfficial(
whatsappOfficialToken
);
whatsappOfficialAPI whatsappOfficialAPI
.post(`/${process.env.VERSION}/${phoneNumberId}/messages`, data) .post(`/${process.env.VERSION}/${phoneNumberId}/messages`, data)

View File

@ -12,14 +12,13 @@ import {
import ffmpeg from "fluent-ffmpeg"; import ffmpeg from "fluent-ffmpeg";
import fs from "fs"; import fs from "fs";
import whatsappOfficialAPI from "./WhatsappOfficialAPI";
import path from "path"; import path from "path";
import { convertAudioToOgg } from "../helpers/ConvertAudio"; import { convertAudioToOgg } from "../helpers/ConvertAudio";
import { bytesToMB } from "./BytesToMB"; import { bytesToMB } from "./BytesToMB";
import isThisHour from "date-fns/esm/isThisHour/index"; import isThisHour from "date-fns/esm/isThisHour/index";
import AppError from "../errors/AppError"; import AppError from "../errors/AppError";
import createApiClientWhatsOfficial from "./WhatsappOfficialAPI";
import Whatsapp from "../models/Whatsapp";
async function sendWhatsMediaOfficialAPI( async function sendWhatsMediaOfficialAPI(
ticket: Ticket, ticket: Ticket,
@ -80,14 +79,6 @@ async function sendWhatsMediaOfficialAPI(
return; return;
} }
const { whatsappOfficialToken }: any = await Whatsapp.findOne({
where: { phoneNumberId }
});
const whatsappOfficialAPI = createApiClientWhatsOfficial(
whatsappOfficialToken
);
whatsappOfficialAPI whatsappOfficialAPI
.post(`/${process.env.VERSION}/${phoneNumberId}/messages`, data) .post(`/${process.env.VERSION}/${phoneNumberId}/messages`, data)
.then(response => { .then(response => {

View File

@ -3,9 +3,6 @@ import { Server } from "http";
import AppError from "../errors/AppError"; import AppError from "../errors/AppError";
import { logger } from "../utils/logger"; import { logger } from "../utils/logger";
import { createAdapter } from "@socket.io/redis-adapter";
import { createClient } from 'redis';
import { v4 as uuidv4 } from "uuid"; import { v4 as uuidv4 } from "uuid";
import ListUserParamiterService from "../services/UserServices/ListUserParamiterService"; import ListUserParamiterService from "../services/UserServices/ListUserParamiterService";
import { import {
@ -30,7 +27,6 @@ import {
} from "../services/WbotServices/wbotMessageListener"; } from "../services/WbotServices/wbotMessageListener";
import { join } from "path"; import { join } from "path";
import Whatsapp from "../models/Whatsapp"; import Whatsapp from "../models/Whatsapp";
import { get } from "../helpers/RedisClient"
let count: number = 0; let count: number = 0;
let listOnline: any[] = []; let listOnline: any[] = [];
@ -46,30 +42,14 @@ let dateTime = splitDateTime(
new Date(format(new Date(), "yyyy-MM-dd HH:mm:ss", { locale: ptBR })) new Date(format(new Date(), "yyyy-MM-dd HH:mm:ss", { locale: ptBR }))
); );
const pubClient = createClient({ url: 'redis://172.31.187.29:6379' });
const subClient = pubClient.duplicate();
pubClient.connect().catch(console.error);
subClient.connect().catch(console.error);
export const initIO = (httpServer: Server): SocketIO => { export const initIO = (httpServer: Server): SocketIO => {
io = new SocketIO(httpServer, { io = new SocketIO(httpServer, {
cors: { cors: {
origin: process.env.FRONTEND_URL, origin: process.env.FRONTEND_URL
//allowedHeaders: ["my-custom-header"],
//credentials: true
}, },
maxHttpBufferSize: 1e8, maxHttpBufferSize: 1e8
// pingInterval: 25000,
// pingTimeout: 60000,
// adapter: createAdapter(pubClient, subClient)
}); });
io.on("connection", socket => { io.on("connection", socket => {
logger.info("Client Connected"); logger.info("Client Connected");
@ -127,7 +107,6 @@ export const initIO = (httpServer: Server): SocketIO => {
socket.on("online", (userId: any) => { socket.on("online", (userId: any) => {
// console.log('userId: ', userId) // console.log('userId: ', userId)
return
obj.uuid = uuidv4(); obj.uuid = uuidv4();
if (userId.logoutUserId) { if (userId.logoutUserId) {
@ -254,18 +233,13 @@ export const initIO = (httpServer: Server): SocketIO => {
if (rooms && rooms.size == 2 && ![...rooms][1].startsWith("session_")) if (rooms && rooms.size == 2 && ![...rooms][1].startsWith("session_"))
return; return;
let whatsappIds = await get({ let whatsappIds: any = await Whatsapp.findAll({
key: "whatsapp:*", attributes: ["id"],
parse: true raw: true
}); });
// let whatsappIds: any = await Whatsapp.findAll({
// attributes: ["id"],
// raw: true
// });
if (whatsappIds && whatsappIds.length > 0) { if (whatsappIds && whatsappIds.length > 0) {
// whatsappIds = whatsappIds.map((e: any) => `${e.id}`); whatsappIds = whatsappIds.map((e: any) => `${e.id}`);
console.log( console.log(
"whatsappIds whatsappIds whatsappIds whatsappIds whatsappIds: ", "whatsappIds whatsappIds whatsappIds whatsappIds whatsappIds: ",

View File

@ -51,9 +51,6 @@ class User extends Model<User> {
@Column @Column
transferToOtherQueues: boolean; transferToOtherQueues: boolean;
@Column
identifier: string;
@Default("admin") @Default("admin")
@Column @Column
profile: string; profile: string;

View File

@ -87,9 +87,6 @@ class Whatsapp extends Model<Whatsapp> {
@UpdatedAt @UpdatedAt
updatedAt: Date; updatedAt: Date;
@Column
whatsappOfficialToken: string;
@HasMany(() => Ticket) @HasMany(() => Ticket)
tickets: Ticket[]; tickets: Ticket[];

View File

@ -64,7 +64,6 @@ const FindOrCreateTicketService = async (
await ticket.update({ await ticket.update({
status: "pending", status: "pending",
userId: null, userId: null,
queueId: null,
unreadMessages unreadMessages
}); });
} }
@ -97,12 +96,7 @@ const FindOrCreateTicketService = async (
if (!ticket) { if (!ticket) {
let status = "pending"; let status = "pending";
if ( if (queues.length > 1 && !botInfo.isOnQueue && !queueId) {
queues.length > 1 &&
!botInfo.isOnQueue &&
!queueId &&
!groupContact
) {
status = "queueChoice"; status = "queueChoice";
} }

View File

@ -12,159 +12,167 @@ import UpdateTicketService from "./UpdateTicketService";
import { getSettingValue } from "../../helpers/WhaticketSettings" import { getSettingValue } from "../../helpers/WhaticketSettings"
import ListWhatsAppsNumber from "../WhatsappService/ListWhatsAppsNumber" import ListWhatsAppsNumber from "../WhatsappService/ListWhatsAppsNumber"
import { getSettingValue } from "../../helpers/WhaticketSettings";
import ListWhatsAppsNumber from "../WhatsappService/ListWhatsAppsNumber";
const FindOrCreateTicketServiceBot = async ( const FindOrCreateTicketServiceBot = async (
contact: Contact, contact: Contact,
whatsappId: number, whatsappId: number,
unreadMessages: number, unreadMessages: number,
groupContact?: Contact groupContact?: Contact
): Promise<any> => { ): Promise<any> => {
try {
// let ticket = await Ticket.findOne({
// where: {
// status: {
// [Op.or]: ["open", "pending", "queueChoice"]
// },
// contactId: groupContact ? groupContact.id : contact.id
// }
// });
let ticket; try {
if (getSettingValue("oneContactChatWithManyWhats")?.value == "enabled") { // let ticket = await Ticket.findOne({
let whats = await ListWhatsAppsNumber(whatsappId); // where: {
// status: {
// [Op.or]: ["open", "pending", "queueChoice"]
// },
// contactId: groupContact ? groupContact.id : contact.id
// }
// });
ticket = await Ticket.findOne({ let ticket;
where: {
status: {
[Op.or]: ["open", "pending", "queueChoice"]
},
contactId: groupContact ? groupContact.id : contact.id,
whatsappId: { [Op.in]: whats.whatsapps.map((w: any) => w.id) }
}
});
} else {
ticket = await Ticket.findOne({
where: {
status: {
[Op.or]: ["open", "pending", "queueChoice"]
},
contactId: groupContact ? groupContact.id : contact.id
}
});
}
const { queues, greetingMessage, phoneNumberId } = if (getSettingValue("oneContactChatWithManyWhats")?.value == "enabled") {
await ShowWhatsAppService(whatsappId);
//Habilitar esse caso queira usar o bot let whats = await ListWhatsAppsNumber(whatsappId);
const botInfo = await BotIsOnQueue("botqueue");
// const botInfo = { isOnQueue: false }
if (ticket) { ticket = await Ticket.findOne({
await ticket.update({ unreadMessages }); where: {
} status: {
[Op.or]: ["open", "pending", "queueChoice"]
// if (!ticket && groupContact) { },
// ticket = await Ticket.findOne({ contactId: groupContact ? groupContact.id : contact.id,
// where: { whatsappId: { [Op.in]: whats.whatsapps.map((w: any) => w.id) }
// 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,
whatsappId: whatsappId
},
order: [["updatedAt", "DESC"]]
});
if (ticket) {
await ticket.update({
status: "open",
userId: botInfo.userIdBot,
unreadMessages
}); });
} else {
ticket = await Ticket.findOne({
where: {
status: {
[Op.or]: ["open", "pending", "queueChoice"]
},
contactId: groupContact ? groupContact.id : contact.id
}
});
}
console.log("lxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); const { queues, greetingMessage, phoneNumberId } =
await ShowWhatsAppService(whatsappId);
await dialogFlowStartContext(contact, ticket, botInfo);
} //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,
whatsappId: whatsappId
},
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,
phoneNumberId
});
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);
} }
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,
phoneNumberId
});
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; export default FindOrCreateTicketServiceBot;
async function dialogFlowStartContext( async function dialogFlowStartContext(contact: Contact, ticket: Ticket, botInfo: any) {
contact: Contact,
ticket: Ticket,
botInfo: any
) {
let msg: any = { type: "chat", from: `${contact.number}@c.us`, body: "0" };
let queue = await ShowQueueService(botInfo.botQueueId); let msg: any = { type: 'chat', from: `${contact.number}@c.us`, body: '0' };
await UpdateTicketService({ let queue = await ShowQueueService(botInfo.botQueueId);
ticketData: { queueId: queue.id },
ticketId: ticket.id
});
ticket = await ShowTicketService(ticket.id); await UpdateTicketService({
ticketData: { queueId: queue.id },
ticketId: ticket.id
});
ticket = await ShowTicketService(ticket.id);
// await sendDialogflowAnswer(ticket.whatsappId, ticket, msg, contact, false);
// await sendDialogflowAnswer(ticket.whatsappId, ticket, msg, contact, false);
} }

View File

@ -469,11 +469,13 @@ const verifyMediaMessage = async (
phoneNumberId: msg?.phoneNumberId, phoneNumberId: msg?.phoneNumberId,
fromAgent: false fromAgent: false
}; };
if(getSettingValue('blockAudioVideoMedia')?.value === 'enabled'){ // if (
if( messageData.mediaType === 'video' || messageData.mediaType === 'audio' ){ // messageData.mediaType === "video" ||
mediaAuthorized = false; // (messageData.mediaType === "audio" &&
} // getSettingValue("blockAudioVideoMedia")?.value === "enabled")
} // ) {
// mediaAuthorized = false;
// }
if (msg?.fromMe) { if (msg?.fromMe) {
messageData = { ...messageData, fromAgent: true }; messageData = { ...messageData, fromAgent: true };
} }
@ -646,6 +648,7 @@ const verifyMessage = async (
quotedMsgId: quotedMsg, quotedMsgId: quotedMsg,
phoneNumberId: msg?.phoneNumberId phoneNumberId: msg?.phoneNumberId
}; };
if (msg?.fromMe) { if (msg?.fromMe) {
const botInfo = await BotIsOnQueue("botqueue"); const botInfo = await BotIsOnQueue("botqueue");
@ -683,12 +686,6 @@ const verifyQueue = async (
ticket: Ticket, ticket: Ticket,
contact: Contact contact: Contact
) => { ) => {
if(ticket?.isGroup){
return
}
const { queues, greetingMessage } = await ShowWhatsAppService(wbot.id!); const { queues, greetingMessage } = await ShowWhatsAppService(wbot.id!);
let selectedOption = null; let selectedOption = null;
@ -1020,7 +1017,7 @@ const handleMessage = async (
try { try {
let msgContact: any = wbot.msgContact; let msgContact: any = wbot.msgContact;
let groupContact: Contact | undefined; // let groupContact: Contact | undefined;
if (msg.fromMe) { if (msg.fromMe) {
// messages sent automatically by wbot have a special character in front of it // messages sent automatically by wbot have a special character in front of it
@ -1060,20 +1057,17 @@ const handleMessage = async (
// console.log('----------> chat: ', JSON.parse(JSON.stringify(chat))) // console.log('----------> chat: ', JSON.parse(JSON.stringify(chat)))
// if (chat.isGroup) {
// let msgGroupContact;
console // if (msg.fromMe) {
// msgGroupContact = await wbot.getContactById(msg.to);
// } else {
// msgGroupContact = await wbot.getContactById(msg.from);
// }
if (chat.isGroup) { // groupContact = await verifyContact(msgGroupContact);
// let msgGroupContact; // }
// if (msg.fromMe) {
// msgGroupContact = await wbot.getContactById(msg.to);
// } else {
// msgGroupContact = await wbot.getContactById(msg.from);
// }
groupContact = await verifyContact(wbot.getContactById);
}
const whatsapp = await ShowWhatsAppService(wbot.id!); const whatsapp = await ShowWhatsAppService(wbot.id!);
@ -1097,12 +1091,12 @@ const handleMessage = async (
const _botInfo = await BotIsOnQueue("botqueue"); const _botInfo = await BotIsOnQueue("botqueue");
if (_botInfo.isOnQueue && !chat.isGroup) { if (_botInfo.isOnQueue) {
let ticket_obj: any = await FindOrCreateTicketServiceBot( let ticket_obj: any = await FindOrCreateTicketServiceBot(
contact, contact,
wbot.id!, wbot.id!,
unreadMessages, unreadMessages
groupContact // groupContact
); );
ticket = ticket_obj.ticket; ticket = ticket_obj.ticket;
@ -1121,8 +1115,8 @@ const handleMessage = async (
ticket = await FindOrCreateTicketService( ticket = await FindOrCreateTicketService(
contact, contact,
wbot.id!, wbot.id!,
unreadMessages, unreadMessages
groupContact // groupContact
); );
} }
@ -2326,7 +2320,7 @@ async function setSoport(ticket: any, wbot: any, contact: any) {
botSendMessage( botSendMessage(
ticket, ticket,
`_*Respuesta*_\n\n*code_resp*: ${code_resp._}\n*msg_resp*: ${msg_resp._}\nGracias por contactarte con nosotros, tu id estará super recomendado... recuerda que te queremos ver , feliz como una lombriz 😃` `_*Respuesta*_\n\n*code_resp*: ${code_resp._}\n*msg_resp*: ${msg_resp._}`
); );
} else { } else {
console.error( console.error(

View File

@ -43,7 +43,7 @@
"yup": "^0.32.8" "yup": "^0.32.8"
}, },
"scripts": { "scripts": {
"start": "PORT=3331 react-scripts start", "start": "react-scripts start",
"build": "react-scripts build", "build": "react-scripts build",
"test": "react-scripts test", "test": "react-scripts test",
"eject": "react-scripts eject" "eject": "react-scripts eject"

View File

@ -45,7 +45,7 @@ import {
import ptBrLocale from "date-fns/locale/pt-BR"; import ptBrLocale from "date-fns/locale/pt-BR";
import esLocale from 'date-fns/locale/es';
const ResponsiveTimePickers = (props) => { const ResponsiveTimePickers = (props) => {
@ -63,7 +63,7 @@ const ResponsiveTimePickers = (props) => {
<Fragment> <Fragment>
<MuiPickersUtilsProvider utils={DateFnsUtils} locale={esLocale}> <MuiPickersUtilsProvider utils={DateFnsUtils} locale={ptBrLocale}>
<TimePicker <TimePicker
variant="outline" variant="outline"
label={props.title} label={props.title}

View File

@ -11,7 +11,6 @@ import { TimePicker, DatePicker } from 'formik-material-ui-pickers'
import DateFnsUtils from '@date-io/date-fns' import DateFnsUtils from '@date-io/date-fns'
import ptBrLocale from "date-fns/locale/pt-BR" import ptBrLocale from "date-fns/locale/pt-BR"
import esLocale from 'date-fns/locale/es';
import { WhatsAppsContext } from "../../context/WhatsApp/WhatsAppsContext" import { WhatsAppsContext } from "../../context/WhatsApp/WhatsAppsContext"
@ -258,7 +257,7 @@ const ConfigModal = ({ open, onClose, change }) => {
}} }}
> >
{({ values, touched, errors, isSubmitting }) => ( {({ values, touched, errors, isSubmitting }) => (
<MuiPickersUtilsProvider utils={DateFnsUtils} locale={esLocale}> <MuiPickersUtilsProvider utils={DateFnsUtils} locale={ptBrLocale}>
<Form> <Form>
<DialogContent dividers> <DialogContent dividers>
@ -300,7 +299,7 @@ const ConfigModal = ({ open, onClose, change }) => {
<Field <Field
component={TimePicker} component={TimePicker}
name="startTimeBus" name="startTimeBus"
label={i18n.t('configModal.titles.startService')} label="Inicio atendimento"
ampm={false} ampm={false}
openTo="hours" openTo="hours"
views={['hours', 'minutes',]} views={['hours', 'minutes',]}
@ -310,7 +309,7 @@ const ConfigModal = ({ open, onClose, change }) => {
<Field <Field
component={TimePicker} component={TimePicker}
name="endTimeBus" name="endTimeBus"
label={i18n.t('configModal.titles.endService')} label="Fim atendimento"
ampm={false} ampm={false}
openTo="hours" openTo="hours"
views={['hours', 'minutes',]} views={['hours', 'minutes',]}
@ -326,13 +325,13 @@ const ConfigModal = ({ open, onClose, change }) => {
checked={values.businessTimeEnable} checked={values.businessTimeEnable}
/> />
} }
label={i18n.t('configModal.titles.enableDisable')} /> label={'Ativar/Desativar'} />
</div> </div>
<div> <div>
<Field <Field
as={TextField} as={TextField}
label={i18n.t('configModal.titles.outOfHours')} label={'Mensagem fora do horário de atendimento'}
type="messageBus" type="messageBus"
multiline multiline
rows={5} rows={5}
@ -356,7 +355,7 @@ const ConfigModal = ({ open, onClose, change }) => {
<Field <Field
component={TimePicker} component={TimePicker}
name="startTimeBusSaturday" name="startTimeBusSaturday"
label={i18n.t('configModal.titles.startService')} label="Inicio atendimentos"
ampm={false} ampm={false}
openTo="hours" openTo="hours"
views={['hours', 'minutes',]} views={['hours', 'minutes',]}
@ -366,7 +365,7 @@ const ConfigModal = ({ open, onClose, change }) => {
<Field <Field
component={TimePicker} component={TimePicker}
name="endTimeBusSaturday" name="endTimeBusSaturday"
label={i18n.t('configModal.titles.endService')} label="Fim atendimento"
ampm={false} ampm={false}
openTo="hours" openTo="hours"
views={['hours', 'minutes',]} views={['hours', 'minutes',]}
@ -382,13 +381,13 @@ const ConfigModal = ({ open, onClose, change }) => {
checked={values.businessTimeEnableSaturday} checked={values.businessTimeEnableSaturday}
/> />
} }
label={i18n.t('configModal.titles.enableDisable')} /> label={'Ativar/Desativar'} />
</div> </div>
<div> <div>
<Field <Field
as={TextField} as={TextField}
label={i18n.t('configModal.titles.outOfHoursSaturday')} label={'Mensagem fora do horário de atendimento sábado'}
type="messageBusSaturday" type="messageBusSaturday"
multiline multiline
rows={5} rows={5}
@ -431,13 +430,13 @@ const ConfigModal = ({ open, onClose, change }) => {
checked={values.enableWeekendMessage} checked={values.enableWeekendMessage}
/> />
} }
label={i18n.t('configModal.titles.enableDisable')} label={'Ativar/Desativar'}
/> />
</div> </div>
<div> <div>
<Field <Field
as={TextField} as={TextField}
label={i18n.t('configModal.titles.forTheWeekend')} label={'Mensagem para final de semana'}
type="weekendMessage" type="weekendMessage"
multiline multiline
rows={5} rows={5}
@ -462,7 +461,7 @@ const ConfigModal = ({ open, onClose, change }) => {
<Field <Field
component={DatePicker} component={DatePicker}
name="holidayDate" name="holidayDate"
label={i18n.t('configModal.titles.holiday')} label="Data do feriado"
format="dd/MM/yyyy" format="dd/MM/yyyy"
fullWidth fullWidth
/> />
@ -476,13 +475,13 @@ const ConfigModal = ({ open, onClose, change }) => {
checked={values.holidayDateEnable} checked={values.holidayDateEnable}
/> />
} }
label={i18n.t('configModal.titles.enableDisable')} label={'Ativar/Desativar'}
/> />
</div> </div>
<div> <div>
<Field <Field
as={TextField} as={TextField}
label={i18n.t('configModal.titles.holidayMessage')} label={'Mensagem para feriado'}
type="holidayDateMessage" type="holidayDateMessage"
multiline multiline
rows={5} rows={5}
@ -525,13 +524,13 @@ const ConfigModal = ({ open, onClose, change }) => {
checked={values.ticketExpirationEnable} checked={values.ticketExpirationEnable}
/> />
} }
label={i18n.t('configModal.titles.enableDisable')} label={'Ativar/Desativar'}
/> />
</div> </div>
<div> <div>
<Field <Field
as={TextField} as={TextField}
label={i18n.t('configModal.titles.inactivityMessage')} label={'Mensagem por falta de atividade no atendimento'}
type="ticketExpirationMsg" type="ticketExpirationMsg"
multiline multiline
rows={5} rows={5}
@ -570,7 +569,7 @@ const ConfigModal = ({ open, onClose, change }) => {
size={24} size={24}
className={classes.buttonProgress} className={classes.buttonProgress}
/> />
) : i18n.t('configModal.titles.save')} ) : 'Salvar'}
</Button> </Button>
</DialogActions> </DialogActions>
</Form> </Form>

View File

@ -23,8 +23,6 @@ import CheckCircleIcon from "@material-ui/icons/CheckCircle";
import ErrorIcon from "@material-ui/icons/Error"; import ErrorIcon from "@material-ui/icons/Error";
import RemoveCircleIcon from "@material-ui/icons/RemoveCircle"; import RemoveCircleIcon from "@material-ui/icons/RemoveCircle";
import { i18n } from "../../translate/i18n";
const CardUser = ({ classes, usersOnlineInfo, logout }) => { const CardUser = ({ classes, usersOnlineInfo, logout }) => {
const [search, setSearch] = React.useState(""); const [search, setSearch] = React.useState("");
@ -48,14 +46,14 @@ const CardUser = ({ classes, usersOnlineInfo, logout }) => {
color="primary" color="primary"
style={{ marginBottom: "16px" }} style={{ marginBottom: "16px" }}
> >
{i18n.t('dashboard.titles.listUser')} Lista de Usuários
</Typography> </Typography>
</Grid> </Grid>
<Grid item sx={8} width="100%"> <Grid item sx={8} width="100%">
<Box sx={{ marginBottom: 2, display: "flex", gap: "12px" }}> <Box sx={{ marginBottom: 2, display: "flex", gap: "12px" }}>
<TextField <TextField
id="outlined-basic" id="outlined-basic"
label={i18n.t('dashboard.titles.user')} label="Usuário"
variant="standard" variant="standard"
value={search} value={search}
onChange={handlesearch} onChange={handlesearch}
@ -72,7 +70,7 @@ const CardUser = ({ classes, usersOnlineInfo, logout }) => {
<MenuItem value={null}>Todos</MenuItem> <MenuItem value={null}>Todos</MenuItem>
<MenuItem value={"online"}>Online</MenuItem> <MenuItem value={"online"}>Online</MenuItem>
<MenuItem value={"offline"}>Offline</MenuItem> <MenuItem value={"offline"}>Offline</MenuItem>
<MenuItem value={"not"}>{i18n.t('dashboard.titles.notEnter')}</MenuItem> <MenuItem value={"not"}>Não entrou</MenuItem>
</Select> </Select>
</FormControl> </FormControl>
</Box> </Box>
@ -163,7 +161,7 @@ const CardUser = ({ classes, usersOnlineInfo, logout }) => {
<Typography component="p" color="textPrimary" paragraph> <Typography component="p" color="textPrimary" paragraph>
{user.sumOnlineTime && user.sumOnlineTime.sum {user.sumOnlineTime && user.sumOnlineTime.sum
? user.sumOnlineTime.sum ? user.sumOnlineTime.sum
: i18n.t('dashboard.titles.notEnterToday')} : "Não entrou Hoje"}
</Typography> </Typography>
</Typography> </Typography>
</CardContent> </CardContent>

View File

@ -75,7 +75,7 @@ const TableUser = ({ classes, usersOnlineInfo, logout }) => {
<MenuItem value={null}>Todos</MenuItem> <MenuItem value={null}>Todos</MenuItem>
<MenuItem value={"online"}>Online</MenuItem> <MenuItem value={"online"}>Online</MenuItem>
<MenuItem value={"offline"}>Offline</MenuItem> <MenuItem value={"offline"}>Offline</MenuItem>
<MenuItem value={"not"}>{i18n.t('dashboard.titles.notEnter')}</MenuItem> <MenuItem value={"not"}>Não entrou</MenuItem>
</Select> </Select>
</FormControl> </FormControl>
</Box> </Box>
@ -221,7 +221,7 @@ const TableUser = ({ classes, usersOnlineInfo, logout }) => {
</div> </div>
</TableCell> </TableCell>
<TableCell> <TableCell>
{user.sumOnlineTime ? user.sumOnlineTime.sum : i18n.t('dashboard.titles.notEnter')} {user.sumOnlineTime ? user.sumOnlineTime.sum : "Não entrou"}
</TableCell> </TableCell>
<TableCell> <TableCell>
{user.statusOnline && user.statusOnline.status === "online" ? ( {user.statusOnline && user.statusOnline.status === "online" ? (

View File

@ -1,9 +1,7 @@
import React, { useContext, useState, useEffect, useReducer, useRef } from "react" import React, { useContext, useState, useEffect, useReducer, useRef } from "react"
import { isSameDay, parseISO, format } from "date-fns" import { isSameDay, parseISO, format } from "date-fns"
//import openSocket from "socket.io-client" import openSocket from "socket.io-client"
import { socket } from "../../services/socket"
import clsx from "clsx" import clsx from "clsx"
import { AuthContext } from "../../context/Auth/AuthContext" import { AuthContext } from "../../context/Auth/AuthContext"
@ -36,7 +34,7 @@ import whatsBackground from "../../assets/wa-background.png"
import api from "../../services/api" import api from "../../services/api"
import toastError from "../../errors/toastError" import toastError from "../../errors/toastError"
import { countTicketMsgContext } from "../../context/CountTicketMsgProvider/CountTicketMsgProvider" import { countTicketMsgContext } from "../../context/CountTicketMsgProvider/CountTicketMsgProvider"
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme) => ({
messagesListWrapper: { messagesListWrapper: {
@ -440,18 +438,11 @@ const MessagesList = ({ ticketId, isGroup }) => {
}, [pageNumber, ticketId]) }, [pageNumber, ticketId])
useEffect(() => { useEffect(() => {
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL) const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
const onConnectMessagesList = () => { socket.on("connect", () => socket.emit("joinChatBox", ticketId))
socket.emit("joinChatBox", ticketId)
}
onConnectMessagesList() socket.on("appMessage", (data) => {
socket.on("connect", onConnectMessagesList)
const onAppMessageMessagesList = (data) => {
if (+data.message.ticketId !== +ticketId) return
if (data.action === "create") { if (data.action === "create") {
@ -463,14 +454,10 @@ const MessagesList = ({ ticketId, isGroup }) => {
if (data.action === "update") { if (data.action === "update") {
dispatch({ type: "UPDATE_MESSAGE", payload: data.message }) dispatch({ type: "UPDATE_MESSAGE", payload: data.message })
} }
} })
socket.on("appMessage", onAppMessageMessagesList)
return () => { return () => {
socket.emit("leaveChatBox", ticketId) socket.disconnect()
socket.off("connect", onConnectMessagesList)
socket.off("appMessage", onAppMessageMessagesList)
} }
}, [ticketId]) }, [ticketId])

View File

@ -13,7 +13,7 @@ import {
import ptBrLocale from "date-fns/locale/pt-BR"; import ptBrLocale from "date-fns/locale/pt-BR";
import esLocale from 'date-fns/locale/es';
function formatDateDatePicker(data){ function formatDateDatePicker(data){
return String(new Date(data).getFullYear())+'-'+ return String(new Date(data).getFullYear())+'-'+
@ -50,7 +50,7 @@ function ResponsiveDatePickers(props) {
return ( return (
<Fragment> <Fragment>
<MuiPickersUtilsProvider utils={DateFnsUtils} locale={esLocale}> <MuiPickersUtilsProvider utils={DateFnsUtils} locale={ptBrLocale}>
<KeyboardDatePicker <KeyboardDatePicker
// autoOk // autoOk

View File

@ -45,7 +45,7 @@ import {
import ptBrLocale from "date-fns/locale/pt-BR"; import ptBrLocale from "date-fns/locale/pt-BR";
import esLocale from 'date-fns/locale/es';
function formatDate(strDate){ function formatDate(strDate){
const date = strDate.split(' ')[0].split('/') const date = strDate.split(' ')[0].split('/')
@ -70,7 +70,7 @@ const ResponsiveTimePickers = (props) => {
<Fragment> <Fragment>
<MuiPickersUtilsProvider utils={DateFnsUtils} locale={esLocale}> <MuiPickersUtilsProvider utils={DateFnsUtils} locale={ptBrLocale}>
<TimePicker <TimePicker
variant="outline" variant="outline"
label={props.title} label={props.title}

View File

@ -2,8 +2,7 @@ import React, { useState, useRef, useEffect, useContext } from "react"
import { useHistory } from "react-router-dom" import { useHistory } from "react-router-dom"
import { format } from "date-fns" import { format } from "date-fns"
//import openSocket from "socket.io-client" import openSocket from "socket.io-client"
import { socket } from "../../services/socket"
import useSound from "use-sound" import useSound from "use-sound"
import Popover from "@material-ui/core/Popover" import Popover from "@material-ui/core/Popover"
@ -116,24 +115,24 @@ const NotificationsPopOver = () => {
useEffect(() => { useEffect(() => {
const fetchSession = async () => { const fetchSession = async () => {
try { try {
const { data } = await api.get('/settings') const { data } = await api.get('/settings')
setSettings(data.settings) setSettings(data.settings)
} catch (err) { } catch (err) {
toastError(err) toastError(err)
} }
} }
fetchSession() fetchSession()
}, []) }, [])
const getSettingValue = (key) => { const getSettingValue = (key) => {
const { value } = settings.find((s) => s.key === key) const { value } = settings.find((s) => s.key === key)
return value return value
} }
useEffect(() => { useEffect(() => {
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL) const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on("reload_page", (data) => { socket.on("reload_page", (data) => {
@ -194,8 +193,7 @@ const NotificationsPopOver = () => {
return () => { return () => {
socket.removeAllListeners('reload_page'); socket.disconnect()
socket.removeAllListeners('onlineStatus');
} }
}, [user.id, handleLogout, user.profile]) }, [user.id, handleLogout, user.profile])
@ -203,17 +201,12 @@ const NotificationsPopOver = () => {
useEffect(() => { useEffect(() => {
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL) const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
const onConnectNotifications = () => { socket.on("connect", () => socket.emit("joinNotification"))
socket.emit("joinNotification")
}
onConnectNotifications()
socket.on("connect", onConnectNotifications) socket.on("ticket", data => {
const onTicketNotifications = data => {
if (data.action === "updateUnread" || data.action === "delete") { if (data.action === "updateUnread" || data.action === "delete") {
@ -239,18 +232,25 @@ const NotificationsPopOver = () => {
return prevState return prevState
}) })
} }
} })
socket.on("appMessage", data => {
socket.on("ticket", onTicketNotifications)
const onAppMessageNotifications = data => {
if ( if (
data.action === "create" && data.action === "create" &&
!data.message.read && !data.message.read &&
(data.ticket.userId === user?.id || !data.ticket.userId) (data.ticket.userId === user?.id || !data.ticket.userId)
) { ) {
setNotifications(prevState => { setNotifications(prevState => {
// prevState.forEach((e)=>{ // prevState.forEach((e)=>{
// //
// }) // })
@ -265,6 +265,8 @@ const NotificationsPopOver = () => {
return [data.ticket, ...prevState] return [data.ticket, ...prevState]
}) })
const shouldNotNotificate = (data.message.ticketId === ticketIdRef.current && document.visibilityState === "visible") || const shouldNotNotificate = (data.message.ticketId === ticketIdRef.current && document.visibilityState === "visible") ||
(data.ticket.userId && data.ticket.userId !== user?.id) || (data.ticket.userId && data.ticket.userId !== user?.id) ||
data.ticket.isGroup || !data.ticket.userId data.ticket.isGroup || !data.ticket.userId
@ -273,25 +275,20 @@ const NotificationsPopOver = () => {
handleNotifications(data) handleNotifications(data)
} }
} })
socket.on("appMessage", onAppMessageNotifications) socket.on('notifyPeding', data =>{
if(settings?.length > 0 && getSettingValue('notificationTransferQueue') === 'enabled') handleNotifications("", data);
socket.on('notifyPeding', data => {
if (settings?.length > 0 && getSettingValue('notificationTransferQueue') === 'enabled') handleNotifications("", data);
}); });
return () => { return () => {
socket.off('connect', onConnectNotifications); socket.disconnect()
socket.off('ticket', onTicketNotifications);
socket.off('appMessage', onAppMessageNotifications);
socket.removeAllListeners('notifyPeding');
} }
}, [user, settings]) }, [user, settings])
const handleNotifications = (data, notify) => { const handleNotifications = (data, notify) => {
let isQueue = false; let isQueue = false;
if (!notify) { if(!notify){
const { message, contact, ticket } = data const { message, contact, ticket } = data
const options = { const options = {
@ -304,10 +301,10 @@ const NotificationsPopOver = () => {
const notification = new Notification( const notification = new Notification(
`${i18n.t("tickets.notification.message")} ${contact.name}`, `${i18n.t("tickets.notification.message")} ${contact.name}`,
options options
) )
notification.onclick = e => { notification.onclick = e => {
e.preventDefault() e.preventDefault()
window.focus() window.focus()
historyRef.current.push(`/tickets/${ticket.id}`) historyRef.current.push(`/tickets/${ticket.id}`)
} }
@ -322,15 +319,15 @@ const NotificationsPopOver = () => {
} }
return [notification, ...prevState] return [notification, ...prevState]
}) })
} else { }else{
user.queues.forEach(queue => { user.queues.forEach(queue =>{
if (queue.id === notify.data?.queue?.id) { if(queue.id === notify.data?.queue?.id){
isQueue = true; isQueue = true;
} }
}) })
if (!isQueue) { if(!isQueue){
return; return;
} else { }else {
const notification = new Notification(`${i18n.t("tickets.notification.messagePeding")} ${notify.data?.queue?.name}`); const notification = new Notification(`${i18n.t("tickets.notification.messagePeding")} ${notify.data?.queue?.name}`);
notification.onclick = e => { notification.onclick = e => {
e.preventDefault() e.preventDefault()
@ -390,10 +387,10 @@ const NotificationsPopOver = () => {
vertical: "top", vertical: "top",
horizontal: "right", horizontal: "right",
}} }}
classes={{ paper: classes?.popoverPaper }} classes={{ paper: classes.popoverPaper }}
onClose={handleClickAway} onClose={handleClickAway}
> >
<List dense className={classes?.tabContainer}> <List dense className={classes.tabContainer}>
{notifications.length === 0 ? ( {notifications.length === 0 ? (
<ListItem> <ListItem>
<ListItemText>{i18n.t("notifications.noTickets")}</ListItemText> <ListItemText>{i18n.t("notifications.noTickets")}</ListItemText>

View File

@ -3,8 +3,8 @@ import React, { useState, useEffect, useRef, useContext } from "react"
import * as Yup from "yup" import * as Yup from "yup"
import { Formik, Form, Field } from "formik" import { Formik, Form, Field } from "formik"
import { toast } from "react-toastify" import { toast } from "react-toastify"
//import openSocket from 'socket.io-client' import openSocket from 'socket.io-client'
import { socket } from "../../services/socket"
import { import {
makeStyles, makeStyles,
@ -87,9 +87,9 @@ const PositionModal = ({
useEffect(() => { useEffect(() => {
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL) const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
const onSettingsPosition = (data) => { socket.on('settings', (data) => {
if (data.action === 'update') { if (data.action === 'update') {
setSettings((prevState) => { setSettings((prevState) => {
const aux = [...prevState] const aux = [...prevState]
@ -98,12 +98,10 @@ const PositionModal = ({
return aux return aux
}) })
} }
} })
socket.on('settings', onSettingsPosition)
return () => { return () => {
socket.off("settings", onSettingsPosition) socket.disconnect()
} }
}, []) }, [])
@ -193,7 +191,7 @@ const PositionModal = ({
<div className={classes.textQuickAnswerContainer}> <div className={classes.textQuickAnswerContainer}>
<Field <Field
as={TextField} as={TextField}
label={i18n.t('dashboard.titles.name')} label={'Nome'}
name="name" name="name"
autoFocus autoFocus
error={touched.name && Boolean(errors.name)} error={touched.name && Boolean(errors.name)}

View File

@ -1,8 +1,6 @@
import React, { useEffect, useState, useContext } from "react"; import React, { useEffect, useState, useContext } from "react";
import QRCode from "qrcode.react"; import QRCode from "qrcode.react";
//import openSocket from "socket.io-client"; import openSocket from "socket.io-client";
import { socket } from "../../services/socket";
import toastError from "../../errors/toastError"; import toastError from "../../errors/toastError";
import { Dialog, DialogContent, Paper, Typography } from "@material-ui/core"; import { Dialog, DialogContent, Paper, Typography } from "@material-ui/core";
@ -33,9 +31,9 @@ const QrcodeModal = ({ open, onClose, whatsAppId }) => {
useEffect(() => { useEffect(() => {
if (!whatsAppId) return; if (!whatsAppId) return;
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL); const socket = openSocket(process.env.REACT_APP_BACKEND_URL);
const onWhatsAppSessionQrCode = data => { socket.on("whatsappSession", data => {
if (data.action === "update" && data.session.id === whatsAppId) { if (data.action === "update" && data.session.id === whatsAppId) {
setQrCode(data.session.qrcode); setQrCode(data.session.qrcode);
} }
@ -46,21 +44,19 @@ const QrcodeModal = ({ open, onClose, whatsAppId }) => {
if (data.action === "error") { if (data.action === "error") {
console.log('user.profile: ', user.profile) console.log('user.profile: ', user.profile)
if (user.profile === 'master') { if(user.profile === 'master'){
alert(data.msg) alert(data.msg)
} }
} }
} });
socket.on("whatsappSession", onWhatsAppSessionQrCode);
return () => { return () => {
socket.off("whatsappSession", onWhatsAppSessionQrCode); socket.disconnect();
}; };
}, [whatsAppId, onClose, user.profile]); }, [whatsAppId, onClose, user.profile]);

View File

@ -23,8 +23,8 @@ import { IconButton, InputAdornment } from "@material-ui/core"
import { Colorize } from "@material-ui/icons" import { Colorize } from "@material-ui/icons"
import { AuthContext } from '../../context/Auth/AuthContext' import { AuthContext } from '../../context/Auth/AuthContext'
//import openSocket from 'socket.io-client' import openSocket from 'socket.io-client'
import { socket } from "../../services/socket"
const useStyles = makeStyles(theme => ({ const useStyles = makeStyles(theme => ({
@ -92,9 +92,9 @@ const QueueModal = ({ open, onClose, queueId }) => {
}, [setting]) }, [setting])
useEffect(() => { useEffect(() => {
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL) const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
const onSettingsQueueModal = (data) => { socket.on('settings', (data) => {
if (data.action === 'update') { if (data.action === 'update') {
setSettings((prevState) => { setSettings((prevState) => {
const aux = [...prevState] const aux = [...prevState]
@ -103,12 +103,10 @@ const QueueModal = ({ open, onClose, queueId }) => {
return aux return aux
}) })
} }
} })
socket.on('settings', onSettingsQueueModal)
return () => { return () => {
socket.off("settings", onSettingsQueueModal) socket.disconnect()
} }
}, []) }, [])

View File

@ -3,8 +3,8 @@ import React, { useState, useEffect, useRef, useContext } from "react"
import * as Yup from "yup" import * as Yup from "yup"
import { Formik, Form, Field } from "formik" import { Formik, Form, Field } from "formik"
import { toast } from "react-toastify" import { toast } from "react-toastify"
//import openSocket from 'socket.io-client' import openSocket from 'socket.io-client'
import { socket } from "../../services/socket"
import { import {
makeStyles, makeStyles,
@ -101,9 +101,9 @@ const QuickAnswersModal = ({
}, [open,]) }, [open,])
useEffect(() => { useEffect(() => {
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL) const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
const onSettingsQuickAnswersModal = (data) => { socket.on('settings', (data) => {
if (data.action === 'update') { if (data.action === 'update') {
setSettings((prevState) => { setSettings((prevState) => {
const aux = [...prevState] const aux = [...prevState]
@ -112,12 +112,10 @@ const QuickAnswersModal = ({
return aux return aux
}) })
} }
} })
socket.on('settings', onSettingsQuickAnswersModal)
return () => { return () => {
socket.off("settings", onSettingsQuickAnswersModal) socket.disconnect()
} }
}, []) }, [])

View File

@ -15,7 +15,7 @@ import {
import ptBrLocale from "date-fns/locale/pt-BR"; import ptBrLocale from "date-fns/locale/pt-BR";
import esLocale from 'date-fns/locale/es';
function formatDateDatePicker(data){ function formatDateDatePicker(data){
return String(new Date(data).getFullYear())+'-'+ return String(new Date(data).getFullYear())+'-'+
@ -52,7 +52,7 @@ function ResponsiveDatePickers(props) {
return ( return (
<Fragment> <Fragment>
<MuiPickersUtilsProvider utils={DateFnsUtils} locale={esLocale}> <MuiPickersUtilsProvider utils={DateFnsUtils} locale={ptBrLocale}>
<KeyboardDatePicker <KeyboardDatePicker
// autoOk // autoOk

View File

@ -52,7 +52,7 @@ const Modal = (props) => {
const dataChat = props.data.map((dt) => { const dataChat = props.data.map((dt) => {
return { return {
'fromMe': dt.fromMe ? i18n.t('dashboard.titles.attendant') : 'Cliente', 'fromMe': dt.fromMe ? 'Atendente' : 'Cliente',
'body': dt.body, 'body': dt.body,
'createdAt': dt.createdAt 'createdAt': dt.createdAt
} }

View File

@ -12,7 +12,6 @@ import InputLabel from '@mui/material/InputLabel';
import MenuItem from '@mui/material/MenuItem'; import MenuItem from '@mui/material/MenuItem';
import Select from '@mui/material/Select'; import Select from '@mui/material/Select';
import { i18n } from "../../translate/i18n";
@ -57,11 +56,11 @@ useEffect(()=>{
open={open} open={open}
onClose={handleClose} onClose={handleClose}
> >
<DialogTitle>{i18n.t('dashboard.titles.dialogTitle')}</DialogTitle> <DialogTitle>Relatórios</DialogTitle>
<DialogContent> <DialogContent>
<DialogContentText> <DialogContentText>
{i18n.t('dashboard.titles.dialogContentText')} Escolha uma opção de relatório abaixo
</DialogContentText> </DialogContentText>
<Box <Box

View File

@ -3,8 +3,8 @@ import React, { useState, useEffect, useRef, useContext } from "react"
import * as Yup from "yup" import * as Yup from "yup"
import { Formik, Form, Field } from "formik" import { Formik, Form, Field } from "formik"
import { toast } from "react-toastify" import { toast } from "react-toastify"
//import openSocket from 'socket.io-client' import openSocket from 'socket.io-client'
import { socket } from "../../services/socket"
import { import {
makeStyles, makeStyles,
@ -91,9 +91,9 @@ const StatusChatEndModal = ({
useEffect(() => { useEffect(() => {
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL) const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
const onSettingsStatusChatEndModal = (data) => { socket.on('settings', (data) => {
if (data.action === 'update') { if (data.action === 'update') {
setSettings((prevState) => { setSettings((prevState) => {
const aux = [...prevState] const aux = [...prevState]
@ -102,12 +102,10 @@ const StatusChatEndModal = ({
return aux return aux
}) })
} }
} })
socket.on('settings', onSettingsStatusChatEndModal)
return () => { return () => {
socket.off("settings", onSettingsStatusChatEndModal) socket.disconnect()
} }
}, []) }, [])

View File

@ -2,9 +2,7 @@ import React, { useState, useEffect } from "react"
import { useParams, useHistory } from "react-router-dom" import { useParams, useHistory } from "react-router-dom"
import { toast } from "react-toastify" import { toast } from "react-toastify"
//import openSocket from "socket.io-client" import openSocket from "socket.io-client"
import { socket } from "../../services/socket"
import clsx from "clsx" import clsx from "clsx"
import { Paper, makeStyles } from "@material-ui/core" import { Paper, makeStyles } from "@material-ui/core"
@ -134,32 +132,22 @@ const Ticket = () => {
}, []) }, [])
useEffect(() => { useEffect(() => {
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL) const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
const onConnectTicket = () => socket.emit("joinChatBox", ticketId) socket.on("connect", () => socket.emit("joinChatBox", ticketId))
onConnectTicket()
socket.on("connect", onConnectTicket)
const onTicketTicket = (data) => {
const isSameTicket = +data?.ticket?.id === +ticketId || +data.ticketId === +ticketId
if (!isSameTicket) return
socket.on("ticket", (data) => {
if (data.action === "update") { if (data.action === "update") {
setTicket(data.ticket) setTicket(data.ticket)
} }
if (data.action === "deleteForever") { if (data.action === "delete") {
console.log('delete forever')
toast.success("Ticket deleted sucessfully.") toast.success("Ticket deleted sucessfully.")
history.push("/tickets") history.push("/tickets")
} }
} })
socket.on("ticket", onTicketTicket) socket.on("contact", (data) => {
const onContactTicket = (data) => {
if (data.action === "update") { if (data.action === "update") {
setContact((prevState) => { setContact((prevState) => {
if (prevState.id === data.contact?.id) { if (prevState.id === data.contact?.id) {
@ -168,11 +156,9 @@ const Ticket = () => {
return prevState return prevState
}) })
} }
} })
socket.on("contact", onContactTicket) socket.on("remoteTickesControllIdleOpen", (data) => {
const onRemoteTicketsControllIdleOpenTicket = (data) => {
if (data.action === "update") { if (data.action === "update") {
let url_ticketId let url_ticketId
try { try {
@ -189,15 +175,10 @@ const Ticket = () => {
console.log('error on try do the send seen: ', error) console.log('error on try do the send seen: ', error)
} }
} }
} })
socket.on("remoteTickesControllIdleOpen", onRemoteTicketsControllIdleOpenTicket)
return () => { return () => {
socket.off("connect", onConnectTicket) socket.disconnect()
socket.off("ticket", onTicketTicket)
socket.off("contact", onContactTicket)
socket.off("remoteTickesControllIdleOpen", onRemoteTicketsControllIdleOpenTicket)
} }
}, [ticketId, history]) }, [ticketId, history])

View File

@ -22,8 +22,7 @@ import MarkdownWrapper from "../MarkdownWrapper"
import { Tooltip } from "@material-ui/core" import { Tooltip } from "@material-ui/core"
import { AuthContext } from "../../context/Auth/AuthContext" import { AuthContext } from "../../context/Auth/AuthContext"
import toastError from "../../errors/toastError" import toastError from "../../errors/toastError"
//import openSocket from 'socket.io-client' import openSocket from 'socket.io-client'
import { socket } from "../../services/socket"
const useStyles = makeStyles(theme => ({ const useStyles = makeStyles(theme => ({
ticket: { ticket: {
@ -152,18 +151,17 @@ const TicketListItem = ({ ticket, remoteTicketsControll, settings }) => {
useEffect(() => { useEffect(() => {
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL) const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
const onRemoteTickesControllTicketListItem = (data) => { socket.on('remoteTickesControll', (data) => {
console.log('REMOTE TICKETS CONTROLL UPDATE2: ', data.tickets) console.log('REMOTE TICKETS CONTROLL UPDATE2: ', data.tickets)
if (data.action === 'update') { if (data.action === 'update') {
setRemoteTicketsControll(data.tickets) setRemoteTicketsControll(data.tickets)
} }
} })
socket.on('remoteTickesControll', onRemoteTickesControllTicketListItem)
const onSettingsTicketListItem = (data) => { socket.on('settings', (data) => {
if (data.action === 'update') { if (data.action === 'update') {
setSettings((prevState) => { setSettings((prevState) => {
const aux = [...prevState] const aux = [...prevState]
@ -172,13 +170,11 @@ const TicketListItem = ({ ticket, remoteTicketsControll, settings }) => {
return aux return aux
}) })
} }
} })
socket.on('settings', onSettingsTicketListItem)
return () => { return () => {
socket.off('remoteTickesControll', onRemoteTickesControllTicketListItem); socket.disconnect()
socket.off('settings', onSettingsTicketListItem);
} }
}, []) }, [])

View File

@ -1,7 +1,7 @@
import React, { useState, useEffect, useReducer, useContext } from "react" import React, { useState, useEffect, useReducer, useContext } from "react"
//import openSocket from "socket.io-client"
import { socket } from "../../services/socket" import openSocket from "socket.io-client"
import { makeStyles } from "@material-ui/core/styles" import { makeStyles } from "@material-ui/core/styles"
import List from "@material-ui/core/List" import List from "@material-ui/core/List"
@ -243,29 +243,27 @@ const TicketsList = (props) => {
// if (tab=='search')return // if (tab=='search')return
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL) const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
const shouldUpdateTicket = ticket => const shouldUpdateTicket = ticket =>
(status === ticket.status) &&
(!ticket.userId || ticket.userId === user?.id || showAll) && (!ticket.userId || ticket.userId === user?.id || showAll) &&
(!ticket.queueId || selectedQueueIds.indexOf(ticket.queueId) > -1) (!ticket.queueId || selectedQueueIds.indexOf(ticket.queueId) > -1)
const notBelongsToUserQueues = ticket => const notBelongsToUserQueues = ticket =>
ticket.queueId && selectedQueueIds.indexOf(ticket.queueId) === -1 ticket.queueId && selectedQueueIds.indexOf(ticket.queueId) === -1
const onConnectTicketList = () => { socket.on("connect", () => {
if (status) { if (status) {
socket.emit("joinTickets", status) socket.emit("joinTickets", status)
} else { } else {
socket.emit("joinNotification") socket.emit("joinNotification")
} }
}
onConnectTicketList() })
socket.on("connect", onConnectTicketList)
const onTicketTicketList = data => {
socket.on("ticket", data => {
if (data.action === "updateUnread") { if (data.action === "updateUnread") {
@ -294,11 +292,10 @@ const TicketsList = (props) => {
if (data.action === "delete") { if (data.action === "delete") {
dispatch({ type: "DELETE_TICKET", payload: data.ticketId }) dispatch({ type: "DELETE_TICKET", payload: data.ticketId })
} }
} })
socket.on("ticket", onTicketTicketList)
const onAppMessageTicketList = data => { socket.on("appMessage", data => {
if (data.action === "create" && shouldUpdateTicket(data.ticket)) { if (data.action === "create" && shouldUpdateTicket(data.ticket)) {
@ -310,9 +307,7 @@ const TicketsList = (props) => {
payload: data, payload: data,
}) })
} }
} })
socket.on("appMessage", onAppMessageTicketList)
socket.on("contact", data => { socket.on("contact", data => {
if (data.action === "update") { if (data.action === "update") {
@ -323,16 +318,16 @@ const TicketsList = (props) => {
} }
}) })
const onRemoteTickesControllTicketList = (data) => {
socket.on('remoteTickesControll', (data) => {
console.log('REMOTE TICKETS CONTROLL UPDATE 1: ', data.tickets) console.log('REMOTE TICKETS CONTROLL UPDATE 1: ', data.tickets)
if (data.action === 'update') { if (data.action === 'update') {
setRemoteTicketsControll(data.tickets) setRemoteTicketsControll(data.tickets)
} }
} })
socket.on('remoteTickesControll', onRemoteTickesControllTicketList)
const onSettingsTicketList = (data) => { socket.on('settings', (data) => {
if (data.action === 'update') { if (data.action === 'update') {
setSettings((prevState) => { setSettings((prevState) => {
const aux = [...prevState] const aux = [...prevState]
@ -341,17 +336,11 @@ const TicketsList = (props) => {
return aux return aux
}) })
} }
} })
socket.on('settings', onSettingsTicketList)
return () => { return () => {
socket.off("ticket", onTicketTicketList) socket.disconnect()
socket.off('appMessage', onAppMessageTicketList);
socket.removeAllListeners("contact")
socket.off('connect', onConnectTicketList);
socket.off('settings', onSettingsTicketList);
socket.off('remoteTickesControll', onRemoteTickesControllTicketList);
} }
}, [status, showAll, user, selectedQueueIds, tab]) }, [status, showAll, user, selectedQueueIds, tab])
@ -360,7 +349,7 @@ const TicketsList = (props) => {
if (typeof updateCount === "function") { if (typeof updateCount === "function") {
updateCount(ticketsList.length) updateCount(ticketsList.length)
} }
if (ticketsList && status === "pending") { if (ticketsList && status === "pending"){
setTickets(ticketsList) setTickets(ticketsList)
} }
// else{ // else{

View File

@ -19,6 +19,7 @@ import FindInPageIcon from '@material-ui/icons/FindInPage'
import FormControlLabel from "@material-ui/core/FormControlLabel" import FormControlLabel from "@material-ui/core/FormControlLabel"
import Switch from "@material-ui/core/Switch" import Switch from "@material-ui/core/Switch"
import openSocket from "socket.io-client"
import NewTicketModal from "../NewTicketModal" import NewTicketModal from "../NewTicketModal"
import TicketsList from "../TicketsList" import TicketsList from "../TicketsList"
@ -152,7 +153,7 @@ const TicketsManager = () => {
const [openCount, setOpenCount] = useState(0) const [openCount, setOpenCount] = useState(0)
const [pendingCount, setPendingCount] = useState(0) const [pendingCount, setPendingCount] = useState(0)
const userQueueIds = user?.queues?.map((q) => q?.id) const userQueueIds = user.queues.map((q) => q.id)
const [selectedQueueIds, setSelectedQueueIds] = useState(userQueueIds || []) const [selectedQueueIds, setSelectedQueueIds] = useState(userQueueIds || [])
const [showContentSearch, setShowContentSearch] = useState(false) const [showContentSearch, setShowContentSearch] = useState(false)
@ -177,9 +178,9 @@ const TicketsManager = () => {
}, [setting]) }, [setting])
useEffect(() => { useEffect(() => {
if (user?.profile?.toUpperCase() === "ADMIN" || if (user.profile.toUpperCase() === "ADMIN" ||
user?.profile?.toUpperCase() === "SUPERVISOR" || user.profile.toUpperCase() === "SUPERVISOR" ||
user?.profile?.toUpperCase() === "MASTER") { user.profile.toUpperCase() === "MASTER") {
setShowAllTickets(true) setShowAllTickets(true)
} }
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
@ -202,11 +203,11 @@ const TicketsManager = () => {
if (tickets.length > 0) { if (tickets.length > 0) {
const now = new Date() const now = new Date()
const differenceTime = tickets?.map(ticket => { const differenceTime = tickets?.map(ticket => {
const createdAt = new Date(ticket?.createdAt) const createdAt = new Date(ticket.createdAt)
const difference = now - createdAt const difference = now - createdAt
return difference return difference
}) })
const sumDifferences = differenceTime?.reduce((total, difference) => total + difference, 0) const sumDifferences = differenceTime.reduce((total, difference) => total + difference, 0)
const averageTimeMilliseconds = sumDifferences / tickets?.length const averageTimeMilliseconds = sumDifferences / tickets?.length
let hours = Math.floor(averageTimeMilliseconds / 3600000) let hours = Math.floor(averageTimeMilliseconds / 3600000)
const minutes = Math.floor((averageTimeMilliseconds % 3600000) / 60000) const minutes = Math.floor((averageTimeMilliseconds % 3600000) / 60000)

View File

@ -1,7 +1,6 @@
import React, { useState, useContext, useMemo, useEffect } from "react" import React, { useState, useContext, useMemo, useEffect } from "react"
import { useHistory } from "react-router-dom" import { useHistory } from "react-router-dom"
//import openSocket from "socket.io-client" import openSocket from "socket.io-client"
import { socket } from "../../services/socket"
import Button from "@material-ui/core/Button" import Button from "@material-ui/core/Button"
import Dialog from "@material-ui/core/Dialog" import Dialog from "@material-ui/core/Dialog"
@ -111,9 +110,9 @@ const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => {
useEffect(() => { useEffect(() => {
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL) const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
const onSettingsTransferTicketModal = (data) => { socket.on('settings', (data) => {
console.log('settings updated ----------------------------xxxxxxxxxxxx') console.log('settings updated ----------------------------xxxxxxxxxxxx')
if (data.action === 'update') { if (data.action === 'update') {
@ -124,12 +123,10 @@ const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => {
return aux return aux
}) })
} }
} })
socket.on('settings', onSettingsTransferTicketModal)
return () => { return () => {
socket.off("settings", onSettingsTransferTicketModal) socket.disconnect()
} }
}, []) }, [])
@ -231,7 +228,7 @@ const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => {
{i18n.t("transferTicketModal.title")} {i18n.t("transferTicketModal.title")}
</DialogTitle> </DialogTitle>
<DialogContent dividers > <DialogContent dividers >
<FormControl variant="outlined" className={classes.maxWidth} style={{ marginBottom: '8px' }}> <FormControl variant="outlined" className={classes.maxWidth} style={{marginBottom: '8px'}}>
{/* <InputLabel>{i18n.t("transferTicketModal.fieldQueueLabel")}</InputLabel> */} {/* <InputLabel>{i18n.t("transferTicketModal.fieldQueueLabel")}</InputLabel> */}
<InputLabel>{'Usuário'}</InputLabel> <InputLabel>{'Usuário'}</InputLabel>
@ -262,7 +259,7 @@ const TransferTicketModal = ({ modalOpen, onClose, ticketid }) => {
required required
> >
<MenuItem style={{ background: "white", }} value={''}>&nbsp;</MenuItem> <MenuItem style={{ background: "white", }} value={''}>&nbsp;</MenuItem>
{queues?.map((queue) => ( {queues.map((queue) => (
<MenuItem <MenuItem
key={queue.id} key={queue.id}
value={queue.id} value={queue.id}

View File

@ -262,7 +262,7 @@ const UserModal = ({ open, onClose, userId, }) => {
/> />
<div className={classes.multFieldLine}> <div className={classes.multFieldLine}>
<label style={{display: 'flex', alignItems:'center'}}> <label style={{display: 'flex', alignItems:'center'}}>
{i18n.t('dashboard.titles.transfer')} Transferir para outras filas
<Switch <Switch
name= 'transferToOtherQueues' name= 'transferToOtherQueues'
checked={checked} checked={checked}

View File

@ -1,7 +1,6 @@
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { useHistory } from 'react-router-dom' import { useHistory } from 'react-router-dom'
//import openSocket from 'socket.io-client' import openSocket from 'socket.io-client'
import { socket } from '../../services/socket'
import { toast } from 'react-toastify' import { toast } from 'react-toastify'
@ -63,19 +62,19 @@ const useAuth = () => {
useEffect(() => { useEffect(() => {
const token = localStorage.getItem('token') const token = localStorage.getItem('token')
; (async () => { ;(async () => {
if (token) { if (token) {
try { try {
const { data } = await api.post('/auth/refresh_token') const { data } = await api.post('/auth/refresh_token')
api.defaults.headers.Authorization = `Bearer ${data.token}` api.defaults.headers.Authorization = `Bearer ${data.token}`
setIsAuth(true) setIsAuth(true)
setUser(data.user) setUser(data.user)
} catch (err) { } catch (err) {
toastError(err) toastError(err)
}
} }
setLoading(false) }
})() setLoading(false)
})()
}, []) }, [])
useEffect(() => { useEffect(() => {
@ -91,7 +90,7 @@ const useAuth = () => {
}, []) }, [])
useEffect(() => { useEffect(() => {
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL) const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on('user', (data) => { socket.on('user', (data) => {
if (data.action === 'update' && data.user.id === user.id) { if (data.action === 'update' && data.user.id === user.id) {
@ -99,7 +98,7 @@ const useAuth = () => {
} }
}) })
const onSettingsAuth = (data) => { socket.on('settings', (data) => {
if (data.action === 'update') { if (data.action === 'update') {
setSetting((prevState) => { setSetting((prevState) => {
const aux = [...prevState] const aux = [...prevState]
@ -108,13 +107,10 @@ const useAuth = () => {
return aux return aux
}) })
} }
} })
socket.on('settings', onSettingsAuth)
return () => { return () => {
socket.removeAllListeners('user'); socket.disconnect()
socket.off('settings', onSettingsAuth);
} }
}, [user]) }, [user])

View File

@ -1,7 +1,5 @@
import { useState, useEffect, useReducer } from "react"; import { useState, useEffect, useReducer } from "react";
//import openSocket from "socket.io-client"; import openSocket from "socket.io-client";
import { socket } from "../../services/socket";
import toastError from "../../errors/toastError"; import toastError from "../../errors/toastError";
@ -128,7 +126,7 @@ const useWhatsApps = () => {
}, []); }, []);
useEffect(() => { useEffect(() => {
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL); const socket = openSocket(process.env.REACT_APP_BACKEND_URL);
socket.on("whatsapp", data => { socket.on("whatsapp", data => {
if (data.action === "update") { if (data.action === "update") {
@ -160,9 +158,7 @@ const useWhatsApps = () => {
return () => { return () => {
socket.removeAllListeners('whatsapp'); socket.disconnect();
socket.removeAllListeners('whatsappSession');
socket.removeAllListeners('whatsappSessionMonit');
}; };
}, []); }, []);

View File

@ -31,8 +31,7 @@ import { i18n } from '../translate/i18n'
import { WhatsAppsContext } from '../context/WhatsApp/WhatsAppsContext' import { WhatsAppsContext } from '../context/WhatsApp/WhatsAppsContext'
import { AuthContext } from '../context/Auth/AuthContext' import { AuthContext } from '../context/Auth/AuthContext'
import { Can } from '../components/Can' import { Can } from '../components/Can'
//import openSocket from 'socket.io-client' import openSocket from 'socket.io-client'
import { socket } from '../services/socket'
import api from '../services/api' import api from '../services/api'
@ -119,9 +118,9 @@ const MainListItems = (props) => {
} }
useEffect(() => { useEffect(() => {
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL) const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
const onSettingsMainListItem = (data) => { socket.on('settings', (data) => {
if (data.action === 'update') { if (data.action === 'update') {
setSettings((prevState) => { setSettings((prevState) => {
const aux = [...prevState] const aux = [...prevState]
@ -130,12 +129,10 @@ const MainListItems = (props) => {
return aux return aux
}) })
} }
} })
socket.on('settings', onSettingsMainListItem)
return () => { return () => {
socket.off('settings', onSettingsMainListItem); socket.disconnect()
} }
}, []) }, [])
@ -192,7 +189,7 @@ const MainListItems = (props) => {
/> />
<ListItemLink <ListItemLink
to="/report" to="/report"
primary={i18n.t("mainDrawer.listItems.reports")} primary="Relatório"
icon={<ReportOutlinedIcon />} icon={<ReportOutlinedIcon />}
/> />
</> </>
@ -245,7 +242,7 @@ const MainListItems = (props) => {
(getSettingValue('hasCampaign') === 'enabled' || user.profile === 'master') && ( (getSettingValue('hasCampaign') === 'enabled' || user.profile === 'master') && (
<ListItemLink <ListItemLink
to="/campaign" to="/campaign"
primary={i18n.t("mainDrawer.listItems.campaign") || 'Campaign'} primary="Campanha"
icon={<CampaignIcon />} icon={<CampaignIcon />}
/> />
) )

View File

@ -1,8 +1,7 @@
import React, { useState, useCallback, useEffect, useReducer, useContext } from 'react' import React, { useState, useCallback, useEffect, useReducer, useContext } from 'react'
import { toast } from 'react-toastify' import { toast } from 'react-toastify'
//import openSocket from 'socket.io-client' import openSocket from 'socket.io-client'
import { socket } from '../../services/socket'
import { makeStyles } from '@material-ui/core/styles' import { makeStyles } from '@material-ui/core/styles'
import { green } from '@material-ui/core/colors' import { green } from '@material-ui/core/colors'
@ -297,9 +296,10 @@ const Campaign = () => {
} }
useEffect(() => { useEffect(() => {
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL) const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
const onContactsBulkCampaing = (data) => {
socket.on("contactsBulkInsertOnQueueStatus", (data) => {
if (data.action === 'update') { if (data.action === 'update') {
if (String(data.insertOnQueue.adminId) === String(user.id)) { if (String(data.insertOnQueue.adminId) === String(user.id)) {
@ -312,24 +312,19 @@ const Campaign = () => {
} }
} }
} })
socket.on("contactsBulkInsertOnQueueStatus", onContactsBulkCampaing) socket.on('campaign', (data) => {
const onCampaignCampaign = (data) => {
if (data.action === 'update') { if (data.action === 'update') {
dispatch({ type: "UPDATE_CAMPAIGNS", payload: data.campaign }) dispatch({ type: "UPDATE_CAMPAIGNS", payload: data.campaign })
} }
} })
socket.on('campaign', onCampaignCampaign)
return () => { return () => {
socket.off("campaign", onCampaignCampaign) socket.disconnect()
socket.off("contactsBulkInsertOnQueueStatus", onContactsBulkCampaing)
} }
}, [user.id]) }, [user.id])

View File

@ -2,8 +2,7 @@ import React, { useState, useCallback, useEffect, useContext } from 'react'
import { toast } from 'react-toastify' import { toast } from 'react-toastify'
import { format, parseISO } from 'date-fns' import { format, parseISO } from 'date-fns'
//import openSocket from 'socket.io-client' import openSocket from 'socket.io-client'
import { socket } from '../../services/socket'
import { makeStyles } from '@material-ui/core/styles' import { makeStyles } from '@material-ui/core/styles'
import { green, red, yellow, grey } from '@material-ui/core/colors' import { green, red, yellow, grey } from '@material-ui/core/colors'
@ -452,17 +451,15 @@ const Connections = () => {
}, []) }, [])
useEffect(() => { useEffect(() => {
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL) const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
const onDiskSpaceMonitConnections = (data) => { socket.on('diskSpaceMonit', (data) => {
if (data.action === 'update') { if (data.action === 'update') {
setDiskSpaceInfo(data.diskSpace) setDiskSpaceInfo(data.diskSpace)
} }
} })
socket.on('diskSpaceMonit', onDiskSpaceMonitConnections) socket.on('settings', (data) => {
const onSettingsConnections = (data) => {
if (data.action === 'update') { if (data.action === 'update') {
setSettings((prevState) => { setSettings((prevState) => {
const aux = [...prevState] const aux = [...prevState]
@ -471,13 +468,10 @@ const Connections = () => {
return aux return aux
}) })
} }
} })
socket.on('settings', onSettingsConnections)
return () => { return () => {
socket.off("settings", onSettingsConnections) socket.disconnect()
socket.off("diskSpaceMonit", onDiskSpaceMonitConnections)
} }
}, []) }, [])

View File

@ -1,6 +1,5 @@
import React, { useState, useEffect, useReducer, useCallback, useContext } from "react" import React, { useState, useEffect, useReducer, useCallback, useContext } from "react"
//import openSocket from "socket.io-client" import openSocket from "socket.io-client"
import { socket } from "../../services/socket"
import { toast } from "react-toastify" import { toast } from "react-toastify"
import { useHistory } from "react-router-dom" import { useHistory } from "react-router-dom"
@ -261,9 +260,9 @@ const Contacts = () => {
}, [searchParam, pageNumber]) }, [searchParam, pageNumber])
useEffect(() => { useEffect(() => {
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL) const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
const onContactsBulkContacts = (data) => { socket.on("contactsBulkInsertOnQueueStatus", (data) => {
if (data.action === 'update') { if (data.action === 'update') {
if (String(data.insertOnQueue.adminId) === String(user.id)) { if (String(data.insertOnQueue.adminId) === String(user.id)) {
@ -279,11 +278,9 @@ const Contacts = () => {
} }
} }
} })
socket.on("contactsBulkInsertOnQueueStatus", onContactsBulkContacts) socket.on("contact", (data) => {
const onContactContacts = (data) => {
if (data.action === "update" || data.action === "create") { if (data.action === "update" || data.action === "create") {
dispatch({ type: "UPDATE_CONTACTS", payload: data.contact }) dispatch({ type: "UPDATE_CONTACTS", payload: data.contact })
} }
@ -291,13 +288,10 @@ const Contacts = () => {
if (data.action === "delete") { if (data.action === "delete") {
dispatch({ type: "DELETE_CONTACT", payload: +data.contactId }) dispatch({ type: "DELETE_CONTACT", payload: +data.contactId })
} }
} })
socket.on("contact", onContactContacts)
return () => { return () => {
socket.off("contact", onContactContacts) socket.disconnect()
socket.off("contactsBulkInsertOnQueueStatus", onContactsBulkContacts)
} }
}, [user, history]) }, [user, history])

View File

@ -5,8 +5,6 @@ import { PieChart as RechartsPieChart, Pie, Cell, ResponsiveContainer, Tooltip }
import Title from './Title'; import Title from './Title';
import { i18n } from "../../translate/i18n";
const generateDataExample = (amount) => { const generateDataExample = (amount) => {
const arr = [] const arr = []
for (let i = 1; i <= amount; i++) { for (let i = 1; i <= amount; i++) {
@ -78,7 +76,7 @@ const PieChart = ({ data = dataExample }) => {
> >
<Box width="100%" height="100%" position="sticky" top="0" zIndex={1000}> <Box width="100%" height="100%" position="sticky" top="0" zIndex={1000}>
<Box sx={{ position: "absolute" }}> <Box sx={{ position: "absolute" }}>
<Title>{i18n.t('dashboard.titles.title')}</Title> <Title>Tickets encerramento</Title>
</Box> </Box>
<ResponsiveContainer width="100%" height="100%"> <ResponsiveContainer width="100%" height="100%">
<RechartsPieChart width={400} height={400}> <RechartsPieChart width={400} height={400}>

View File

@ -14,11 +14,10 @@ import Info from "@material-ui/icons/Info"
import SelectField from "../../components/Report/SelectField" import SelectField from "../../components/Report/SelectField"
import { AuthContext } from "../../context/Auth/AuthContext" import { AuthContext } from "../../context/Auth/AuthContext"
import { i18n } from "../../translate/i18n"; // import { i18n } from "../../translate/i18n";
import Chart from "./Chart" import Chart from "./Chart"
import PieChart from "./PieChart" import PieChart from "./PieChart"
//import openSocket from "socket.io-client" import openSocket from "socket.io-client"
import { socket } from "../../services/socket"
import api from "../../services/api" import api from "../../services/api"
import { Can } from "../../components/Can" import { Can } from "../../components/Can"
@ -357,54 +356,46 @@ const Dashboard = () => {
useEffect(() => { useEffect(() => {
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL) const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
const onTicketsStatusDashboard = (data) => { socket.on("ticketStatus", (data) => {
if (data.action === "update") { if (data.action === "update") {
setStatus("") setStatus("")
setStatus(data.ticketStatus.status) setStatus(data.ticketStatus.status)
} }
} })
socket.on("ticketStatus", onTicketsStatusDashboard) socket.on("onlineStatus", (data) => {
const onOnlineStatusDashboard = (data) => {
if (data.action === "logout" || data.action === "update") { if (data.action === "logout" || data.action === "update") {
dispatch({ type: "UPDATE_STATUS_ONLINE", payload: data.userOnlineTime }) dispatch({ type: "UPDATE_STATUS_ONLINE", payload: data.userOnlineTime })
} else if (data.action === "delete") { } else if (data.action === "delete") {
dispatch({ type: "DELETE_USER_STATUS", payload: data.userOnlineTime }) dispatch({ type: "DELETE_USER_STATUS", payload: data.userOnlineTime })
} }
} })
socket.on("onlineStatus", onOnlineStatusDashboard) socket.on("user", (data) => {
const onUserDashboard = (data) => {
if (data.action === "delete") { if (data.action === "delete") {
dispatch({ type: "DELETE_USER", payload: +data.userId }) dispatch({ type: "DELETE_USER", payload: +data.userId })
} }
} })
socket.on("user", onUserDashboard)
return () => { return () => {
socket.off("user", onUserDashboard) socket.disconnect()
socket.off("onlineStatus", onOnlineStatusDashboard)
socket.off("ticketStatus", onTicketsStatusDashboard)
} }
}, []) }, [])
const handleSelectedQueue = useCallback((queueSelected) => { const handleSelectedQueue = useCallback((queueSelected) => {
if (queueSelected !== 'All') { if(queueSelected !== 'All'){
const queueIndex = user?.queues?.findIndex((q) => q.id === parseInt(queueSelected)); const queueIndex = user?.queues?.findIndex((q) => q.id === parseInt(queueSelected));
const queueIds = [] const queueIds = []
queueIds.push(user?.queues[queueIndex]?.id); queueIds.push(user?.queues[queueIndex]?.id);
setSelectedQueue(queueIds); setSelectedQueue(queueIds);
} else { }else{
const queueIds = user?.queues?.map((queue) => queue.id); const queueIds = user?.queues?.map((queue) => queue.id);
setSelectedQueue(queueIds); setSelectedQueue(queueIds);
} }
}, [user, setSelectedQueue]) },[user, setSelectedQueue])
useEffect(() => { useEffect(() => {
if (ticketStatusChange === "") return if (ticketStatusChange === "") return
@ -481,7 +472,7 @@ const Dashboard = () => {
func={handleSelectedQueue} func={handleSelectedQueue}
textBoxFieldSelected={'All'} textBoxFieldSelected={'All'}
emptyField={false} emptyField={false}
header={i18n.t('dashboard.titles.selectQueues')} header={'Filas'}
currencies={user.queues.map((obj) => { currencies={user.queues.map((obj) => {
return { 'value': obj.id, 'label': obj.name } return { 'value': obj.id, 'label': obj.name }
})} /> })} />
@ -494,7 +485,7 @@ const Dashboard = () => {
variant="outlined" variant="outlined"
> >
<Typography component="h3" variant="h6" color="primary" paragraph> <Typography component="h3" variant="h6" color="primary" paragraph>
{i18n.t('dashboard.titles.waiting')} Aguardando
</Typography> </Typography>
<Grid item> <Grid item>
<Typography component="h1" variant="h4"> <Typography component="h1" variant="h4">
@ -510,7 +501,7 @@ const Dashboard = () => {
variant="outlined" variant="outlined"
> >
<Typography component="h3" variant="h6" color="primary" style={{ marginBottom: "0" }} paragraph> <Typography component="h3" variant="h6" color="primary" style={{ marginBottom: "0" }} paragraph>
{i18n.t('dashboard.titles.inService')} Em Atendimento
</Typography> </Typography>
<Typography paragraph style={{ fontSize: "12px", margin: "0px" }}>Hoje/Todo Periodo</Typography> <Typography paragraph style={{ fontSize: "12px", margin: "0px" }}>Hoje/Todo Periodo</Typography>
@ -529,7 +520,7 @@ const Dashboard = () => {
variant="outlined" variant="outlined"
> >
<Typography component="h3" variant="h6" color="primary" paragraph> <Typography component="h3" variant="h6" color="primary" paragraph>
{i18n.t('dashboard.titles.ticketsClosed')} Fechados
</Typography> </Typography>
<Grid item> <Grid item>
<Typography component="h1" variant="h4"> <Typography component="h1" variant="h4">
@ -541,7 +532,7 @@ const Dashboard = () => {
<Grid item container spacing={3}> <Grid item container spacing={3}>
<Grid item xs={12} sm={12} md={6} lg={6}> <Grid item xs={12} sm={12} md={6} lg={6}>
<Paper className={classes.fixedHeightPaper} variant="outlined"> <Paper className={classes.fixedHeightPaper} variant="outlined">
<Chart allTickets={usersOnlineInfo} selectedQueue={selectedQueue} /> <Chart allTickets={usersOnlineInfo} selectedQueue = {selectedQueue}/>
</Paper> </Paper>
</Grid> </Grid>
<Grid item xs={12} sm={12} md={6} lg={6}> <Grid item xs={12} sm={12} md={6} lg={6}>
@ -560,7 +551,7 @@ const Dashboard = () => {
color="primary" color="primary"
style={{ marginBottom: "16px" }} style={{ marginBottom: "16px" }}
> >
{i18n.t('dashboard.titles.users')} Usuários
<Tooltip <Tooltip
title={`Os dados informados abaixo é baseado na data: ${new Date().toLocaleDateString( title={`Os dados informados abaixo é baseado na data: ${new Date().toLocaleDateString(
"pt-BR", "pt-BR",

View File

@ -1,6 +1,5 @@
import React, { useState, useContext, useEffect, useReducer } from "react" import React, { useState, useContext, useEffect, useReducer } from "react"
//import openSocket from "socket.io-client" import openSocket from "socket.io-client"
import { socket } from "../../services/socket"
import { import {
Button, Button,
@ -126,9 +125,9 @@ const Position = () => {
}, [searchParam, pageNumber]) }, [searchParam, pageNumber])
useEffect(() => { useEffect(() => {
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL) const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
const onPositionPosition = (data) => { socket.on("position", (data) => {
if (data.action === "update" || data.action === "create") { if (data.action === "update" || data.action === "create") {
dispatch({ type: "UPDATE_POSITIONS", payload: data.position }) dispatch({ type: "UPDATE_POSITIONS", payload: data.position })
} }
@ -139,12 +138,10 @@ const Position = () => {
payload: +data.positionId, payload: +data.positionId,
}) })
} }
} })
socket.on("position", onPositionPosition)
return () => { return () => {
socket.off("position", onPositionPosition) socket.disconnect()
} }
}, []) }, [])

View File

@ -1,7 +1,6 @@
import React, { useEffect, useReducer, useState, useContext } from 'react' import React, { useEffect, useReducer, useState, useContext } from 'react'
//import openSocket from 'socket.io-client' import openSocket from 'socket.io-client'
import { socket } from '../../services/socket'
import { import {
Button, Button,
@ -124,9 +123,9 @@ const Queues = () => {
}, []) }, [])
useEffect(() => { useEffect(() => {
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL) const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
const onQueueQueues = (data) => { socket.on('queue', (data) => {
if (data.action === 'update' || data.action === 'create') { if (data.action === 'update' || data.action === 'create') {
dispatch({ type: 'UPDATE_QUEUES', payload: data.queue }) dispatch({ type: 'UPDATE_QUEUES', payload: data.queue })
} }
@ -134,11 +133,9 @@ const Queues = () => {
if (data.action === 'delete') { if (data.action === 'delete') {
dispatch({ type: 'DELETE_QUEUE', payload: data.queueId }) dispatch({ type: 'DELETE_QUEUE', payload: data.queueId })
} }
} })
socket.on('queue', onQueueQueues) socket.on('settings', (data) => {
const onSettingsQueues = (data) => {
if (data.action === 'update') { if (data.action === 'update') {
setSettings((prevState) => { setSettings((prevState) => {
const aux = [...prevState] const aux = [...prevState]
@ -147,13 +144,10 @@ const Queues = () => {
return aux return aux
}) })
} }
} })
socket.on('settings', onSettingsQueues)
return () => { return () => {
socket.off("settings", onSettingsQueues) socket.disconnect()
socket.off("queue", onQueueQueues)
} }
}, []) }, [])

View File

@ -1,6 +1,5 @@
import React, { useState, useContext, useEffect, useReducer } from "react" import React, { useState, useContext, useEffect, useReducer } from "react"
//import openSocket from "socket.io-client" import openSocket from "socket.io-client"
import { socket } from "../../services/socket"
import { import {
Button, Button,
@ -126,9 +125,9 @@ const QuickAnswers = () => {
}, [searchParam, pageNumber]) }, [searchParam, pageNumber])
useEffect(() => { useEffect(() => {
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL) const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
const onQuickAnswerQuickAnswers = (data) => { socket.on("quickAnswer", (data) => {
if (data.action === "update" || data.action === "create") { if (data.action === "update" || data.action === "create") {
dispatch({ type: "UPDATE_QUICK_ANSWERS", payload: data.quickAnswer }) dispatch({ type: "UPDATE_QUICK_ANSWERS", payload: data.quickAnswer })
} }
@ -139,11 +138,10 @@ const QuickAnswers = () => {
payload: +data.quickAnswerId, payload: +data.quickAnswerId,
}) })
} }
} })
socket.on("quickAnswer", onQuickAnswerQuickAnswers)
return () => { return () => {
socket.off("quickAnswer", onQuickAnswerQuickAnswers) socket.disconnect()
} }
}, []) }, [])

View File

@ -18,24 +18,23 @@ import MaterialTable from 'material-table'
import LogoutIcon from '@material-ui/icons/CancelOutlined' import LogoutIcon from '@material-ui/icons/CancelOutlined'
import apiBroker from "../../services/apiBroker" import apiBroker from "../../services/apiBroker"
import fileDownload from 'js-file-download' import fileDownload from 'js-file-download'
//import openSocket from "socket.io-client" import openSocket from "socket.io-client"
import { socket } from "../../services/socket"
import { i18n } from "../../translate/i18n" import { i18n } from "../../translate/i18n"
import Switch from '@mui/material/Switch' import Switch from '@mui/material/Switch'
const label = { inputProps: { 'aria-label': 'Size switch demo' } } const label = { inputProps: { 'aria-label': 'Size switch demo' } }
const report = [ const report = [
{ 'value': '1', 'label': `${i18n.t("reports.listTitles.title1_1")}` }, { 'value': '1', 'label': 'Atendimento por atendentes' },
{ 'value': '2', 'label': `${i18n.t("reports.listTitles.title3_1")}` }, { 'value': '2', 'label': 'Usuários online/offline' },
{ 'value': '3', 'label': `${i18n.t("reports.listTitles.title4_1")}` }, { 'value': '3', 'label': 'Relatorio de atendimento por numeros' },
{ 'value': '4', 'label': `${i18n.t("reports.listTitles.title5_1")}` }, { 'value': '4', 'label': 'Relatorio de atendimento por filas' },
] ]
const reportOptType = [ const reportOptType = [
{ 'value': '1', 'label': i18n.t('reportOptType.listTitles.title1') }, { 'value': '1', 'label': 'Padrão' },
{ 'value': '2', 'label': i18n.t('reportOptType.listTitles.title2') }, { 'value': '2', 'label': 'Sintético' },
{ 'value': '3', 'label': i18n.t('reportOptType.listTitles.title3') } { 'value': '3', 'label': 'Analítico' }
] ]
@ -382,10 +381,10 @@ const Report = () => {
const tickets = data.tickets.map(ticket => { const tickets = data.tickets.map(ticket => {
ticket.isRemote = ticket.isRemote ? 'Remoto' : 'Comum'; ticket.isRemote = ticket.isRemote ? 'Remoto' : 'Comum';
return ({ return ({
...ticket, ...ticket,
messagesToFilter: ticket.messages.map(message => message.body).join(' '), messagesToFilter: ticket.messages.map(message => message.body).join(' '),
link: `${process.env.REACT_APP_FRONTEND_URL}/tickets/${ticket.id}` link: `${process.env.REACT_APP_FRONTEND_URL}/tickets/${ticket.id}`
}) })
}) })
dispatchQ({ type: "LOAD_QUERY", payload: tickets }) dispatchQ({ type: "LOAD_QUERY", payload: tickets })
setHasMore(data.hasMore) setHasMore(data.hasMore)
@ -592,9 +591,9 @@ const Report = () => {
useEffect(() => { useEffect(() => {
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL) const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
const onQueryOnQueueStatusReport = (data) => { socket.on("queryOnQueueStatus", (data) => {
if (data.action === 'update') { if (data.action === 'update') {
if (String(data.queryOnQueue.adminId) === String(userA.id)) { if (String(data.queryOnQueue.adminId) === String(userA.id)) {
@ -605,39 +604,35 @@ const Report = () => {
} }
} }
} })
socket.on("queryOnQueueStatus", onQueryOnQueueStatusReport)
const onOnlineStatusReport = (data) => {
let date = new Date().toLocaleDateString('pt-BR').split('/')
let dateToday = `${date[2]}-${date[1]}-${date[0]}`
if (data.action === "logout" || (data.action === "update" &&
((`${startDate}` === `${endDate}`) && (`${endDate}` === `${dateToday}`) && (`${startDate}` === `${dateToday}`)))) {
dispatchQ({ type: "UPDATE_STATUS_ONLINE", payload: data.userOnlineTime })
}
else if (data.action === "delete") {
dispatchQ({ type: "DELETE_USER_STATUS", payload: data.userOnlineTime })
}
}
const onUserReport = (data) => {
if (data.action === "delete") {
dispatch({ type: "DELETE_USER", payload: +data.userId })
}
}
if (reportOption === '2') { if (reportOption === '2') {
socket.on("onlineStatus", onOnlineStatusReport)
socket.on("user", onUserReport) socket.on("onlineStatus", (data) => {
let date = new Date().toLocaleDateString('pt-BR').split('/')
let dateToday = `${date[2]}-${date[1]}-${date[0]}`
if (data.action === "logout" || (data.action === "update" &&
((`${startDate}` === `${endDate}`) && (`${endDate}` === `${dateToday}`) && (`${startDate}` === `${dateToday}`)))) {
dispatchQ({ type: "UPDATE_STATUS_ONLINE", payload: data.userOnlineTime })
}
else if (data.action === "delete") {
dispatchQ({ type: "DELETE_USER_STATUS", payload: data.userOnlineTime })
}
})
socket.on("user", (data) => {
if (data.action === "delete") {
dispatch({ type: "DELETE_USER", payload: +data.userId })
}
})
} }
else if (reportOption === "1") { else if (reportOption === "1") {
@ -646,9 +641,7 @@ const Report = () => {
} }
return () => { return () => {
socket.off("onlineStatus", onOnlineStatusReport) socket.disconnect()
socket.off("user", onUserReport)
socket.off("queryOnQueueStatus", onQueryOnQueueStatusReport)
} }
@ -694,7 +687,7 @@ const Report = () => {
const renderSwitch = (param) => { const renderSwitch = (param) => {
if (userA.profile !== 'supervisor') { if(userA.profile !== 'supervisor'){
switch (param) { switch (param) {
case 'empty': case 'empty':
return ( return (
@ -845,11 +838,11 @@ const Report = () => {
<Box sx={{ display: 'flex', flexDirection: 'column', padding: '10px 0', }}> <Box sx={{ display: 'flex', flexDirection: 'column', padding: '10px 0', }}>
<FormControlLabel <FormControlLabel
control={<Checkbox checked={selectedValue === 'created'} onChange={() => handleCheckBoxChange('created')} />} control={<Checkbox checked={selectedValue === 'created'} onChange={() => handleCheckBoxChange('created')} />}
label="Creado" label="Criado"
/> />
<FormControlLabel <FormControlLabel
control={<Checkbox checked={selectedValue === 'updated'} onChange={() => handleCheckBoxChange('updated')} />} control={<Checkbox checked={selectedValue === 'updated'} onChange={() => handleCheckBoxChange('updated')} />}
label="Actualizado" label="Atualizado"
/> />
</Box> : </Box> :
@ -887,7 +880,7 @@ const Report = () => {
<> <>
<MTable data={query} <MTable data={query}
columns={userA.profile !== 'supervisor' ? columnsData : columnsDataSuper} columns={userA.profile !== 'supervisor' ? columnsData : columnsDataSuper}
hasChild={userA.profile !== 'supervisor' ? true : false} hasChild={userA.profile !== 'supervisor' ? true :false}
removeClickRow={false} removeClickRow={false}
handleScroll={handleScroll} handleScroll={handleScroll}
@ -903,7 +896,7 @@ const Report = () => {
localization={{ localization={{
header: { header: {
actions: 'Unidad' actions: 'Deslogar'
}, },
}} }}
@ -913,7 +906,7 @@ const Report = () => {
[ [
// { title: 'Foto', field: 'ticket.contact.profilePicUrl', render: rowData => <img src={rowData['ticket.contact.profilePicUrl']} alt="imagem de perfil do whatsapp" style={{ width: 40, borderRadius: '50%' }} /> }, // { title: 'Foto', field: 'ticket.contact.profilePicUrl', render: rowData => <img src={rowData['ticket.contact.profilePicUrl']} alt="imagem de perfil do whatsapp" style={{ width: 40, borderRadius: '50%' }} /> },
{ title: 'Nombre', field: 'name', cellStyle: { whiteSpace: 'nowrap' }, }, { title: 'Nome', field: 'name', cellStyle: { whiteSpace: 'nowrap' }, },
{ {
title: 'Status', field: 'statusOnline.status', title: 'Status', field: 'statusOnline.status',
@ -942,11 +935,11 @@ const Report = () => {
}, },
{ title: `${i18n.t('reports.onlineTime')}`, field: 'sumOnlineTime.sum' }, { title: 'Tempo online', field: 'sumOnlineTime.sum' },
{ title: `${i18n.t("reports.dateStart")}`, field: 'startDate' }, { title: `${i18n.t("reports.dateStart")}`, field: 'startDate' },
{ title: `${i18n.t("reports.dateEnd")}`, field: 'endDate' }, { title: `${i18n.t("reports.dateEnd")}`, field: 'endDate' },
{ title: `${i18n.t('reports.inService')}`, field: 'sumOpen.count' }, { title: 'Em atendimento', field: 'sumOpen.count' },
{ title: `${i18n.t('reports.finished')}`, field: 'sumClosed.count' }, { title: 'Finalizado', field: 'sumClosed.count' },
] ]
} }
@ -1008,20 +1001,20 @@ const Report = () => {
title={i18n.t("reports.listTitles.title4_1")} title={i18n.t("reports.listTitles.title4_1")}
columns={ columns={
!checkedRemote ? [ !checkedRemote ? [
{ title: i18n.t('reports.listColumns.column3_1'), field: 'name', cellStyle: { whiteSpace: 'nowrap' }, }, { title: 'Unidade', field: 'name', cellStyle: { whiteSpace: 'nowrap' }, },
{ title: i18n.t('reports.listColumns.column3_3'), field: 'startedByAgent', }, { title: 'Conversas iniciadas', field: 'startedByAgent', },
{ title: i18n.t('reports.listColumns.column3_4'), field: 'startedByClient' }, { title: 'Conversas recebidas', field: 'startedByClient' },
{ title: i18n.t('reports.listColumns.column3_5'), field: 'closedChat' }, { title: `Conversas finalizadas`, field: 'closedChat' },
{ title: i18n.t('reports.listColumns.column3_6'), field: 'avgChatWaitingTime' }, { title: `Tempo médio de espera`, field: 'avgChatWaitingTime' },
{ title: i18n.t('reports.listColumns.column3_7'), field: 'pendingChat' } { title: 'Aguardando', field: 'pendingChat' }
] : ] :
[ [
{ title: i18n.t('reports.listColumns.column3_1'), field: 'name', cellStyle: { whiteSpace: 'nowrap' }, }, { title: 'Unidade', field: 'name', cellStyle: { whiteSpace: 'nowrap' }, },
{ title: i18n.t('reports.listColumns.column3_3'), field: 'startedByAgent', }, { title: 'Conversas iniciadas', field: 'startedByAgent', },
{ title: i18n.t('reports.listColumns.column3_4'), field: 'startedByClient' }, { title: 'Conversas respondidas', field: 'startedByClient' },
{ title: i18n.t('reports.listColumns.column3_5'), field: 'closedChat' }, { title: `Conversas finalizadas`, field: 'closedChat' },
{ title: i18n.t('reports.listColumns.column3_7'), field: 'pendingChat' } { title: 'Aguardando', field: 'pendingChat' }
] ]
} }
@ -1061,9 +1054,9 @@ const Report = () => {
columns={ columns={
!checkedRemote ? [ !checkedRemote ? [
{ title: i18n.t('reports.listColumns.column3_1'), field: 'name', cellStyle: { whiteSpace: 'nowrap' }, }, { title: 'Unidade', field: 'name', cellStyle: { whiteSpace: 'nowrap' }, },
{ {
title: i18n.t('reports.listColumns.column3_2'), field: 'queueName', title: 'Fila', field: 'queueName',
cellStyle: (evt, rowData) => { cellStyle: (evt, rowData) => {
return { return {
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
@ -1073,19 +1066,19 @@ const Report = () => {
} }
}, },
{ title: i18n.t('reports.listColumns.column3_3'), field: 'startedByAgent', }, { title: 'Conversas iniciadas', field: 'startedByAgent', },
{ title: i18n.t('reports.listColumns.column3_4'), field: 'startedByClient' }, { title: 'Conversas recebidas', field: 'startedByClient' },
{ title: i18n.t('reports.listColumns.column3_5'), field: 'closedChat' }, { title: `Conversas finalizadas`, field: 'closedChat' },
{ title: i18n.t('reports.listColumns.column3_6'), field: 'avgChatWaitingTime' }, { title: `Tempo médio de espera`, field: 'avgChatWaitingTime' },
{ title: i18n.t('reports.listColumns.column3_7'), field: 'pendingChat' } { title: 'Aguardando', field: 'pendingChat' }
] : ] :
[ [
{ title: i18n.t('reports.listColumns.column3_1'), field: 'name', cellStyle: { whiteSpace: 'nowrap' }, }, { title: 'Unidade', field: 'name', cellStyle: { whiteSpace: 'nowrap' }, },
{ {
title: i18n.t('reports.listColumns.column3_2'), field: 'queueName', title: 'Fila', field: 'queueName',
cellStyle: (evt, rowData) => { cellStyle: (evt, rowData) => {
return { return {
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
@ -1095,10 +1088,10 @@ const Report = () => {
} }
}, },
{ title: i18n.t('reports.listColumns.column3_3'), field: 'startedByAgent', }, { title: 'Conversas iniciadas', field: 'startedByAgent', },
{ title: i18n.t('reports.listColumns.column3_4'), field: 'startedByClient' }, { title: 'Conversas respondidas', field: 'startedByClient' },
{ title: i18n.t('reports.listColumns.column3_5'), field: 'closedChat' }, { title: `Conversas finalizadas`, field: 'closedChat' },
{ title: i18n.t('reports.listColumns.column3_7'), field: 'pendingChat' } { title: 'Aguardando', field: 'pendingChat' }
] ]
} }

View File

@ -28,8 +28,8 @@ import { render } from '@testing-library/react'
// import Modal from "../../../..ChatEnd/ModalChatEnd"; // import Modal from "../../../..ChatEnd/ModalChatEnd";
import Modal from "../../components/ModalUpdateScheduleReminder" import Modal from "../../components/ModalUpdateScheduleReminder"
//import openSocket from "socket.io-client" import openSocket from "socket.io-client"
import { socket } from "../../services/socket"
@ -204,9 +204,11 @@ const SchedulesReminder = () => {
useEffect(() => { useEffect(() => {
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL) const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
socket.on("schedulingNotify", (data) => {
const onSchedulingNotifySchedulesRemider = (data) => {
setLoading(true) setLoading(true)
@ -226,12 +228,10 @@ const SchedulesReminder = () => {
setLoading(false) setLoading(false)
} })
socket.on("schedulingNotify", onSchedulingNotifySchedulesRemider)
return () => { return () => {
socket.off("schedulingNotify", onSchedulingNotifySchedulesRemider) socket.disconnect()
} }
}, []) }, [])

View File

@ -1,6 +1,5 @@
import React, { useState, useEffect, useContext } from 'react' import React, { useState, useEffect, useContext } from 'react'
//import openSocket from 'socket.io-client' import openSocket from 'socket.io-client'
import { socket } from '../../services/socket.js'
import { makeStyles } from '@material-ui/core/styles' import { makeStyles } from '@material-ui/core/styles'
import Paper from '@material-ui/core/Paper' import Paper from '@material-ui/core/Paper'
@ -125,9 +124,9 @@ const Settings = () => {
useEffect(() => { useEffect(() => {
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL) const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
const onSettingsSettings = (data) => { socket.on('settings', (data) => {
console.log('settings updated ----------------------------') console.log('settings updated ----------------------------')
if (data.action === 'update') { if (data.action === 'update') {
@ -138,12 +137,10 @@ const Settings = () => {
return aux return aux
}) })
} }
} })
socket.on('settings', onSettingsSettings)
return () => { return () => {
socket.off("settings", onSettingsSettings) socket.disconnect()
} }
}, []) }, [])
@ -182,11 +179,7 @@ const Settings = () => {
} }
const getSettingValue = (key, _obj = false) => { const getSettingValue = (key, _obj = false) => {
//const { value, obj } = settings.find((s) => s.key === key) const { value, obj } = settings.find((s) => s.key === key)
const setting = settings.find((s) => s.key === key)
const value = setting?.value || ""
const obj = setting?.obj || null
if (_obj) if (_obj)
return obj return obj

View File

@ -1,6 +1,5 @@
import React, { useState, useContext, useEffect, useReducer } from "react" import React, { useState, useContext, useEffect, useReducer } from "react"
//import openSocket from "socket.io-client" import openSocket from "socket.io-client"
import { socket } from "../../services/socket"
import { import {
Button, Button,
@ -132,9 +131,9 @@ const StatusChatEnd = () => {
}, [searchParam, pageNumber]) }, [searchParam, pageNumber])
useEffect(() => { useEffect(() => {
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL) const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
const onStatusChatEndStatusChatEnd = (data) => { socket.on("statusChatEnd", (data) => {
if (data.action === "update" || data.action === "create") { if (data.action === "update" || data.action === "create") {
dispatch({ type: "UPDATE_STATUS_CHAT_END", payload: data.statusChatEnd }) dispatch({ type: "UPDATE_STATUS_CHAT_END", payload: data.statusChatEnd })
} }
@ -145,12 +144,10 @@ const StatusChatEnd = () => {
payload: +data.statusChatEndId, payload: +data.statusChatEndId,
}) })
} }
} })
socket.on("statusChatEnd", onStatusChatEndStatusChatEnd)
return () => { return () => {
socket.off("statusChatEnd", onStatusChatEndStatusChatEnd) socket.disconnect()
} }
}, []) }, [])
@ -220,7 +217,7 @@ const StatusChatEnd = () => {
<ConfirmationModal <ConfirmationModal
title={ title={
deletingStatusChatEnds && deletingStatusChatEnds &&
`${i18n.t('dashboard.titles.confirmationModal')} ${deletingStatusChatEnds.name `Você tem certeza que quer excluir esta Status de encerramento: ${deletingStatusChatEnds.name
}?` }?`
} }
open={confirmModalOpen} open={confirmModalOpen}
@ -236,7 +233,7 @@ const StatusChatEnd = () => {
statusChatEndId={selectedStatusChatEnd && selectedStatusChatEnd.id} statusChatEndId={selectedStatusChatEnd && selectedStatusChatEnd.id}
></StatusChatEndModal> ></StatusChatEndModal>
<MainHeader> <MainHeader>
<Title>{i18n.t('dashboard.titles.status')}</Title> <Title>{"Status de encerramento"}</Title>
<MainHeaderButtonsWrapper> <MainHeaderButtonsWrapper>
<TextField <TextField
placeholder={i18n.t("quickAnswers.searchPlaceholder")} placeholder={i18n.t("quickAnswers.searchPlaceholder")}
@ -269,13 +266,13 @@ const StatusChatEnd = () => {
<TableHead> <TableHead>
<TableRow> <TableRow>
<TableCell align="center"> <TableCell align="center">
{i18n.t('dashboard.titles.status')} {"Status de encerramento"}
</TableCell> </TableCell>
<TableCell align="center"> <TableCell align="center">
{i18n.t('quickAnswers.table.farewellMessage')} {"Mensagem de despedida"}
</TableCell> </TableCell>
<TableCell align="center"> <TableCell align="center">
{i18n.t('quickAnswers.table.standard')} {"Padrão"}
</TableCell> </TableCell>
<TableCell align="center"> <TableCell align="center">
{i18n.t("quickAnswers.table.actions")} {i18n.t("quickAnswers.table.actions")}

View File

@ -1,7 +1,6 @@
import React, { useState, useEffect, useReducer, useContext } from "react" import React, { useState, useEffect, useReducer, useContext } from "react"
import { toast } from "react-toastify" import { toast } from "react-toastify"
//import openSocket from "socket.io-client" import openSocket from "socket.io-client"
import { socket } from "../../services/socket"
import { makeStyles } from "@material-ui/core/styles" import { makeStyles } from "@material-ui/core/styles"
import Paper from "@material-ui/core/Paper" import Paper from "@material-ui/core/Paper"
@ -166,9 +165,9 @@ const Users = () => {
useEffect(() => { useEffect(() => {
//const socket = openSocket(process.env.REACT_APP_BACKEND_URL) const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
const onUserUsers = (data) => { socket.on("user", (data) => {
if (data.action === "update" || data.action === "create") { if (data.action === "update" || data.action === "create") {
dispatch({ type: "UPDATE_USERS", payload: data.user }) dispatch({ type: "UPDATE_USERS", payload: data.user })
} }
@ -176,11 +175,10 @@ const Users = () => {
if (data.action === "delete") { if (data.action === "delete") {
dispatch({ type: "DELETE_USER", payload: +data.userId }) dispatch({ type: "DELETE_USER", payload: +data.userId })
} }
} })
socket.on("user", onUserUsers)
const onSettingsUsers = (data) => { socket.on('settings', (data) => {
if (data.action === 'update') { if (data.action === 'update') {
setSettings((prevState) => { setSettings((prevState) => {
const aux = [...prevState] const aux = [...prevState]
@ -189,12 +187,10 @@ const Users = () => {
return aux return aux
}) })
} }
} })
socket.on('settings', onSettingsUsers)
return () => { return () => {
socket.off("settings", onSettingsUsers) socket.disconnect()
socket.off("user", onUserUsers)
} }
}, []) }, [])

View File

@ -1,14 +0,0 @@
import { io } from 'socket.io-client';
// "undefined" means the URL will be computed from the `window.location` object
const URL = process.env.REACT_APP_BACKEND_URL
export const socket = io(URL,
//{
// withCredentials: true,
// extraHeaders: {
// "my-custom-header": "abcd"
// },
// transports: ['websocket', 'polling']
//}
);

View File

@ -51,53 +51,14 @@ const messages = {
} }
}, },
table_users: { table_users:{
title: 'User List', title: 'User List',
column0: 'Name', column0: 'Name',
column1: 'In Service/Finished', column1: 'In Service/Finished',
column2: 'Open by Queue', column2: 'Open by Queue',
column3: 'Closed by Queue', column3: 'Closed by Queue',
column4: 'Online time', column4: 'Online time',
column5: 'Actions', column5: 'Actions',
},
titles: {
selectQueues: 'Queues',
waiting: 'In Waiting',
inService: 'In Service',
users: 'Users',
name: 'Name',
attendant: 'Attendant',
dialogContentText: 'Choose a reporting option below.',
transfer: 'Transfer to other queues',
title: 'Closing tickets',
confirmationModal: 'Are you sure you want to remove this closing state: ',
status: 'Closing status',
listUser: 'List user',
user: 'user',
notEnter: 'Did not enter',
notEnterToday: 'Did not enter today',
ticketsClosed: 'Closed'
}
},
reportOptType: {
listTitles: {
title1: 'Standard',
title2: 'Synthetic',
title3: 'Analytical'
}
},
configModal: {
titles: {
startService: 'Start Service',
endService: 'End Service',
enableDisable: 'Enable/Disable',
outOfHours: 'Message outside opening hours',
outOfHoursSaturday: 'Message outside opening hours Saturday',
forTheWeekend: 'Weekend message',
holiday: 'Holiday date',
holidayMessage: 'Message for holidays',
inactivityMessage: 'Message due to lack of service activity',
save: 'Save'
} }
}, },
connections: { connections: {
@ -334,8 +295,7 @@ const messages = {
administration: "Administration", administration: "Administration",
users: "Users", users: "Users",
settings: "Settings", settings: "Settings",
schedules: "Schedules", schedules: "Schedules"
reports: "Reports"
}, },
appBar: { appBar: {
user: { user: {
@ -349,11 +309,9 @@ const messages = {
title0_1: "Reminders/Schedulings", title0_1: "Reminders/Schedulings",
title1_1: "Calls by attendants", title1_1: "Calls by attendants",
title2_1: "Whatsapp chat", title2_1: "Whatsapp chat",
title3_1: "Users online/offline", title3_1: "Users online/offline"
title4_1: "Attendance report by numbers",
title5_1: "Queue service report"
}, },
listColumns: { listColumns:{
column0_1: 'Actions', column0_1: 'Actions',
column0_2: 'Pic', column0_2: 'Pic',
column0_3: 'Name', column0_3: 'Name',
@ -372,22 +330,13 @@ const messages = {
column1_9: 'Closing status', column1_9: 'Closing status',
column2_1: 'Attendant/Client', column2_1: 'Attendant/Client',
column3_1: 'Unit',
column3_2: 'Row',
column3_3: 'Conversations started',
column3_4: 'Incoming conversations',
column3_5: 'Finished conversations',
column3_6: 'Average waiting time',
column3_7: 'Waiting',
}, },
search: 'Number/Name...', search: 'Number/Name...',
dateStart: 'Start date', dateStart: 'Start date',
dateEnd: 'End date', dateEnd: 'End date',
user: 'User', user: 'User'
onlineTime: 'Online time',
inService: 'In service',
finished: 'Finished'
}, },
notifications: { notifications: {
noTickets: "No notifications.", noTickets: "No notifications.",
@ -418,8 +367,6 @@ const messages = {
shortcut: "Shortcut", shortcut: "Shortcut",
message: "Quick Reply", message: "Quick Reply",
actions: "Actions", actions: "Actions",
farewellMessage: "Farewell message",
standard: "Standard"
}, },
buttons: { buttons: {
add: "Add Quick Reply", add: "Add Quick Reply",

View File

@ -52,55 +52,15 @@ const messages = {
} }
}, },
table_users: { table_users:{
title: 'Lista de usuarios', title: 'Lista de usuarios',
column0: 'Nombre', column0: 'Nombre',
column1: 'En servicio/Terminado(S)', column1: 'En servicio/Terminado(S)',
column2: 'Abrir por cola', column2: 'Abrir por cola',
column3: 'Cerrado por cola', column3: 'Cerrado por cola',
column4: 'Tiempo Online', column4: 'Tiempo Online',
column5: 'Actions', column5: 'Actions',
},
titles: {
selectQueues: 'Colas',
waiting: 'En espera',
inService: 'En Atendimiento',
users: 'Usuarios',
name: 'Nombre',
attendant: 'Agente',
dialogTitle: 'Reportes',
dialogContentText: 'Escoja una opción de reporte abajo.',
transfer: 'Transferir para otras Colas',
title: 'Cierre de Tickets',
confirmationModal: 'Está seguro de que desea eliminar este estado de cierre: ',
status: 'Status de cierre',
listUser: 'Lista de Usuarios',
user: 'Usuario',
notEnter: 'No ingresó',
notEnterToday: 'No ingresó hoy',
ticketsClosed: 'Cerrados'
}
},
reportOptType: {
listTitles: {
title1: 'Patrón',
title2: 'Sintético',
title3: 'Analítico'
}
},
configModal: {
titles: {
startService: 'Inicio atención',
endService: 'Fin atención',
enableDisable: 'Activar/Desactivar',
outOfHours: 'Mensaje fuera de horario de atención',
outOfHoursSaturday: 'Mensaje fuera del horario de atención sábado',
forTheWeekend: 'Mensaje fin de semana',
holiday: 'Día Festivo',
holidayMessage: 'Mensaje para Festivos',
inactivityMessage: 'Mensaje por falta de actividad',
save: 'Guardar'
} }
}, },
connections: { connections: {
@ -277,7 +237,7 @@ const messages = {
}, },
}, },
ticketsQueueSelect: { ticketsQueueSelect: {
placeholder: "Líneas", placeholder: "Linhas",
}, },
tickets: { tickets: {
toasts: { toasts: {
@ -336,13 +296,11 @@ const messages = {
tickets: "Tickets", tickets: "Tickets",
contacts: "Contactos", contacts: "Contactos",
quickAnswers: "Respuestas rápidas", quickAnswers: "Respuestas rápidas",
queues: "Líneas", queues: "Linhas",
administration: "Administración", administration: "Administración",
users: "Usuarios", users: "Usuarios",
settings: "Configuración", settings: "Configuración",
schedules: "Recordatorio", schedules: "Recordatorio"
reports: "Reportes",
campain: "Campañas"
}, },
appBar: { appBar: {
user: { user: {
@ -354,13 +312,11 @@ const messages = {
reports: { reports: {
listTitles: { listTitles: {
title0_1: "Recordatorios/Programación", title0_1: "Recordatorios/Programación",
title1_1: "Atención por agentes", title1_1: "Llamadas de asistentes",
title2_1: "Chat de whatsapp", title2_1: "Chat de whatsapp",
title3_1: "Usuarios online/offline", title3_1: "Usuarios online/offline"
title4_1: "Reporte de atención por números",
title5_1: "Reporte de atención por colas"
}, },
listColumns: { listColumns:{
column0_1: 'Acción', column0_1: 'Acción',
column0_2: 'Pic', column0_2: 'Pic',
column0_3: 'Nombre', column0_3: 'Nombre',
@ -379,28 +335,18 @@ const messages = {
column1_9: 'Estado de cierre', column1_9: 'Estado de cierre',
column2_1: 'Secretario/Cliente', column2_1: 'Secretario/Cliente',
column3_1: 'Unidad',
column3_2: 'Cola',
column3_3: 'Chats iniciados',
column3_4: 'Chats Recibidos',
column3_5: 'Chats Finalizados',
column3_6: 'Tiempo medio de espera',
column3_7: 'En Espera',
}, },
search: 'Número/Nombre...', search: 'Número/Nombre...',
dateStart: 'Fecha de inicio', dateStart: 'Fecha de inicio',
dateEnd: 'Fecha final', dateEnd: 'Fecha final',
user: 'Usuario', user: 'Usuario'
onlineTime: 'Tiempo online',
inService: 'En servicio',
finished: 'Finalizado'
}, },
notifications: { notifications: {
noTickets: "Sin notificaciones.", noTickets: "Sin notificaciones.",
}, },
queues: { queues: {
title: "Líneas", title: "Linhas",
table: { table: {
name: "Nombre", name: "Nombre",
color: "Color", color: "Color",
@ -417,7 +363,7 @@ const messages = {
}, },
}, },
queueSelect: { queueSelect: {
inputLabel: "Líneas", inputLabel: "Linhas",
}, },
quickAnswers: { quickAnswers: {
title: "Respuestas rápidas", title: "Respuestas rápidas",
@ -425,8 +371,6 @@ const messages = {
shortcut: "Atajo", shortcut: "Atajo",
message: "Respuesta rápida", message: "Respuesta rápida",
actions: "Acciones", actions: "Acciones",
farewellMessage: "Mensaje de despedida",
standard: "Patrón"
}, },
buttons: { buttons: {
add: "Agregar respuesta rápida", add: "Agregar respuesta rápida",

View File

@ -59,46 +59,6 @@ const messages = {
column3: 'Fechados Por Fila', column3: 'Fechados Por Fila',
column4: 'Tempo Online', column4: 'Tempo Online',
column5: 'Ações', column5: 'Ações',
},
titles: {
selectQueues: 'Filas',
waiting: 'Em espera',
inService: 'Em Atendimento',
users: 'Usuários',
name: 'Nome',
attendant: 'Atendente',
dialogTitle: 'Relatórios',
dialogContentText: 'Escolha uma opção de relatório abaixo.',
transfer: 'Transferir para outras filas',
title: 'Tickets encerramento',
confirmationModal: 'Você tem certeza que quer excluir esta Status de encerramento: ' ,
status: 'Status de encerramento',
listUser: 'Lista de Usuarios',
user: 'Usuario',
notEnter: 'Não entrou',
notEnterToday: 'Não entrou hoje',
ticketsClosed: 'Fechados'
}
},
reportOptType: {
listTitles: {
title1: 'Padrão',
title2: 'Sintético',
title3: 'Analítico'
}
},
configModal: {
titles: {
startService: 'Início atendimento',
endService: 'Fim atendimento',
enableDisable: 'Ativar/Desativar',
outOfHours: 'Mensagem fora do horário de atendimento',
outOfHoursSaturday: 'Mensagem fora do horário de atendimento sábado',
forTheWeekend: 'Mensagem fim de semana',
holiday: 'Data do feriado',
holidayMessage: 'Mensagem para feriados',
inactivityMessage: 'Mensagem por falta de atividade no atendimento',
save: 'Salvar'
} }
}, },
connections: { connections: {
@ -339,9 +299,7 @@ const messages = {
administration: "Administração", administration: "Administração",
users: "Usuários", users: "Usuários",
settings: "Configurações", settings: "Configurações",
schedules: "Lembretes", schedules: "Lembretes"
reports: "Relatórios",
campaign: "Campanha"
}, },
appBar: { appBar: {
user: { user: {
@ -379,21 +337,13 @@ const messages = {
column2_1: 'Atendente/Cliente', column2_1: 'Atendente/Cliente',
column3_1: 'Unidade',
column3_2: 'Fila',
column3_3: 'Conversas iniciadas',
column3_4: 'Conversas recebidas',
column3_5: 'Conversas finalizadas',
column3_6: 'Tempo médio de espera',
column3_7: 'Aguardando',
}, },
search: 'Numer/Nome...', search: 'Numer/Nome...',
dateStart: 'Data início', dateStart: 'Data início',
dateEnd: 'Data fim', dateEnd: 'Data fim',
user: 'Usuário', user: 'Usuário'
onlineTime: 'Tempo online',
inService: 'Em atendimento',
finished: 'Finalizado'
}, },
notifications: { notifications: {
noTickets: "Nenhuma notificação.", noTickets: "Nenhuma notificação.",
@ -424,8 +374,6 @@ const messages = {
shortcut: "Atalho", shortcut: "Atalho",
message: "Resposta Rápida", message: "Resposta Rápida",
actions: "Ações", actions: "Ações",
farewellMessage: "Mensagem de despedida",
standard: "Padrão"
}, },
buttons: { buttons: {
add: "Adicionar Resposta Rápida", add: "Adicionar Resposta Rápida",