Compare commits
5 Commits
051e1b3b2a
...
0d32fe8fbb
Author | SHA1 | Date |
---|---|---|
adriano | 0d32fe8fbb | |
adriano | dcf471fa42 | |
adriano | fd5d9829e4 | |
adriano | c57811c9f6 | |
adriano | 088274cafd |
|
@ -30,8 +30,6 @@ app.get('/', function (req, res) {
|
||||||
app.post('/api/session', async function (req, res) {
|
app.post('/api/session', async function (req, res) {
|
||||||
let { app_name, whatsappId, client_url, number } = req.body
|
let { app_name, whatsappId, client_url, number } = req.body
|
||||||
|
|
||||||
let oldNumber = ''
|
|
||||||
|
|
||||||
if (app_name) {
|
if (app_name) {
|
||||||
app_name = app_name.trim()
|
app_name = app_name.trim()
|
||||||
}
|
}
|
||||||
|
@ -69,7 +67,6 @@ app.post('/api/session', async function (req, res) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let appPort = []
|
let appPort = []
|
||||||
|
|
||||||
let existSubDir = false
|
let existSubDir = false
|
||||||
|
@ -101,7 +98,7 @@ app.post('/api/session', async function (req, res) {
|
||||||
path.join(sessionsPath, directoriesInDIrectory[i], subDir[x])
|
path.join(sessionsPath, directoriesInDIrectory[i], subDir[x])
|
||||||
)
|
)
|
||||||
|
|
||||||
oldNumber = subDir[x].split('_')[1]
|
let oldNumber = subDir[x].split('_')[1]
|
||||||
|
|
||||||
if (oldNumber != number) {
|
if (oldNumber != number) {
|
||||||
deletePm2Process(subDir[x], currPath)
|
deletePm2Process(subDir[x], currPath)
|
||||||
|
@ -200,7 +197,7 @@ app.post('/api/session', async function (req, res) {
|
||||||
) {
|
) {
|
||||||
const whatsapp_numbers = await new Promise((resolve, reject) => {
|
const whatsapp_numbers = await new Promise((resolve, reject) => {
|
||||||
mysql_conn(db_credentials.db_conf).query(
|
mysql_conn(db_credentials.db_conf).query(
|
||||||
'SELECT name, number FROM Whatsapps WHERE name LIKE ?',
|
'SELECT name FROM Whatsapps WHERE name LIKE ?',
|
||||||
[`%${number}%`],
|
[`%${number}%`],
|
||||||
(err, result) => {
|
(err, result) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -212,6 +209,8 @@ app.post('/api/session', async function (req, res) {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
console.log('whatsapp_numbers: ', whatsapp_numbers)
|
||||||
|
|
||||||
let session_num = []
|
let session_num = []
|
||||||
|
|
||||||
if (whatsapp_numbers && whatsapp_numbers.length > 0) {
|
if (whatsapp_numbers && whatsapp_numbers.length > 0) {
|
||||||
|
@ -290,7 +289,7 @@ app.post('/api/session', async function (req, res) {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
if (whatsapp[0]['name']?.split('->')?.length > 0) {
|
if (whatsapp[0]['name'].split('->').length > 0) {
|
||||||
whatsName = `${whatsapp[0]['name'].split('->')[0]} -> S${numberSession}`
|
whatsName = `${whatsapp[0]['name'].split('->')[0]} -> S${numberSession}`
|
||||||
} else {
|
} else {
|
||||||
whatsName = `${whatsapp[0]['name']} -> S${numberSession}`
|
whatsName = `${whatsapp[0]['name']} -> S${numberSession}`
|
||||||
|
@ -342,7 +341,6 @@ app.post('/api/session', async function (req, res) {
|
||||||
stream.write('# NUMBER AND NAME THAT WILL BE DISPLAYED ON CONSOLE\n')
|
stream.write('# NUMBER AND NAME THAT WILL BE DISPLAYED ON CONSOLE\n')
|
||||||
stream.write(`MOBILEUID=${number}\n`)
|
stream.write(`MOBILEUID=${number}\n`)
|
||||||
stream.write(`MOBILENAME=${whatsappName}\n`)
|
stream.write(`MOBILENAME=${whatsappName}\n`)
|
||||||
stream.write(`OLD_MOBILEUID=${oldNumber}\n`)
|
|
||||||
stream.write('\n')
|
stream.write('\n')
|
||||||
|
|
||||||
stream.write('# PORT NUMBER FOR THIS API\n')
|
stream.write('# PORT NUMBER FOR THIS API\n')
|
||||||
|
|
|
@ -288,6 +288,8 @@ client.on("ready", async () => {
|
||||||
|
|
||||||
let url = process.env.CLIENT_URL + '/whatsapp/connection/number'
|
let url = process.env.CLIENT_URL + '/whatsapp/connection/number'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
await client.logout()
|
await client.logout()
|
||||||
|
@ -302,48 +304,6 @@ client.on("ready", async () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (process.env.OLD_MOBILEUID) {
|
|
||||||
const ticketSettingsId = await new Promise((resolve, reject) => {
|
|
||||||
|
|
||||||
dbcc.query("select id from SettingTickets where number = ?", [process.env.OLD_MOBILEUID,], (err, result) => {
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
reject(err)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// resolve(result)
|
|
||||||
const idArray = result.map(row => row.id)
|
|
||||||
resolve(idArray)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
if (ticketSettingsId?.length > 0) {
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
const idsToUpdate = ticketSettingsId // Assuming ticketSettingsId is an array of IDs
|
|
||||||
|
|
||||||
// Create placeholders for the IN clause based on the number of elements in idsToUpdate
|
|
||||||
const placeholders = Array(idsToUpdate.length).fill('?').join(',')
|
|
||||||
|
|
||||||
dbcc.query(
|
|
||||||
`UPDATE SettingTickets SET number = ? WHERE id IN (${placeholders})`,
|
|
||||||
[client.info["wid"]["user"], ...idsToUpdate], // Spread the array to pass individual values
|
|
||||||
function (err, result) {
|
|
||||||
if (err) {
|
|
||||||
console.log("ERROR: " + err)
|
|
||||||
reject(err)
|
|
||||||
} else {
|
|
||||||
resolve(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
|
|
||||||
|
@ -364,6 +324,7 @@ client.on("ready", async () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let url = process.env.CLIENT_URL + '/whatsapp/connection/qrcode'
|
let url = process.env.CLIENT_URL + '/whatsapp/connection/qrcode'
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -1232,9 +1193,9 @@ function comercialBuss(until_hour) {
|
||||||
|
|
||||||
scheduler_monitor = setInterval(monitor, 10000)
|
scheduler_monitor = setInterval(monitor, 10000)
|
||||||
|
|
||||||
// scheduler_campaign_monitor = setInterval(sendCampaignMessage, 3000)
|
scheduler_campaign_monitor = setInterval(sendCampaignMessage, 3000)
|
||||||
|
|
||||||
// scheduler_internet_conn = setInterval(internetMonitor, 60000)
|
scheduler_internet_conn = setInterval(internetMonitor, 60000)
|
||||||
|
|
||||||
app.listen(process.env.PORT || 8003, function () {
|
app.listen(process.env.PORT || 8003, function () {
|
||||||
console.log("\u26A1[server]: Server is running at Port ::: " + process.env.PORT || 8003)
|
console.log("\u26A1[server]: Server is running at Port ::: " + process.env.PORT || 8003)
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
NODE_ENV=
|
||||||
|
BACKEND_URL=http://localhost
|
||||||
|
FRONTEND_URL=http://localhost:3000
|
||||||
|
PROXY_PORT=8080
|
||||||
|
PORT=8080
|
||||||
|
|
||||||
|
DB_DIALECT=
|
||||||
|
DB_HOST=
|
||||||
|
DB_USER=
|
||||||
|
DB_PASS=
|
||||||
|
DB_NAME=
|
||||||
|
|
||||||
|
JWT_SECRET=
|
||||||
|
JWT_REFRESH_SECRET=
|
|
@ -16,7 +16,6 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry/node": "^5.29.2",
|
"@sentry/node": "^5.29.2",
|
||||||
"@types/fluent-ffmpeg": "^2.1.21",
|
|
||||||
"@types/pino": "^6.3.4",
|
"@types/pino": "^6.3.4",
|
||||||
"axios": "^1.2.3",
|
"axios": "^1.2.3",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
|
@ -29,7 +28,6 @@
|
||||||
"express-async-errors": "^3.1.1",
|
"express-async-errors": "^3.1.1",
|
||||||
"fast-folder-size": "^1.7.0",
|
"fast-folder-size": "^1.7.0",
|
||||||
"flat": "^5.0.2",
|
"flat": "^5.0.2",
|
||||||
"fluent-ffmpeg": "^2.1.2",
|
|
||||||
"fs-extra": "^10.1.0",
|
"fs-extra": "^10.1.0",
|
||||||
"http-graceful-shutdown": "^2.3.2",
|
"http-graceful-shutdown": "^2.3.2",
|
||||||
"ioredis": "^5.2.3",
|
"ioredis": "^5.2.3",
|
||||||
|
@ -44,7 +42,6 @@
|
||||||
"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",
|
|
||||||
"socket.io": "^3.0.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",
|
||||||
|
|
|
@ -22,7 +22,6 @@ app.use(
|
||||||
origin: process.env.FRONTEND_URL
|
origin: process.env.FRONTEND_URL
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
app.use(cookieParser());
|
app.use(cookieParser());
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
app.use(Sentry.Handlers.requestHandler());
|
app.use(Sentry.Handlers.requestHandler());
|
||||||
|
|
|
@ -93,7 +93,7 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
number: Yup.string()
|
number: Yup.string()
|
||||||
.required()
|
.required()
|
||||||
.matches(/^\d+$/, "Invalid number format. Only numbers is allowed.")
|
.matches(/^\d+$/, "Invalid number format. Only numbers is allowed.")
|
||||||
// .matches(/^55\d+$/, "The number must start with 55.")
|
.matches(/^55\d+$/, "The number must start with 55.")
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -102,8 +102,6 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
throw new AppError(err.message);
|
throw new AppError(err.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
newContact.number = addStartPhoneNumber(newContact.number);
|
|
||||||
|
|
||||||
const validNumber = await CheckIsValidContact(newContact.number);
|
const validNumber = await CheckIsValidContact(newContact.number);
|
||||||
|
|
||||||
// const validNumber: any = await CheckContactNumber(newContact.number)
|
// const validNumber: any = await CheckContactNumber(newContact.number)
|
||||||
|
@ -159,11 +157,9 @@ export const update = async (
|
||||||
|
|
||||||
const schema = Yup.object().shape({
|
const schema = Yup.object().shape({
|
||||||
name: Yup.string(),
|
name: Yup.string(),
|
||||||
number: Yup.string().matches(
|
number: Yup.string()
|
||||||
/^\d+$/,
|
.matches(/^\d+$/, "Invalid number format. Only numbers is allowed.")
|
||||||
"Invalid number format. Only numbers is allowed."
|
.matches(/^55\d+$/, "The number must start with 55.")
|
||||||
)
|
|
||||||
// .matches(/^55\d+$/, "The number must start with 55.")
|
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -172,8 +168,6 @@ export const update = async (
|
||||||
throw new AppError(err.message);
|
throw new AppError(err.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
contactData.number = addStartPhoneNumber(contactData.number);
|
|
||||||
|
|
||||||
await CheckIsValidContact(contactData.number);
|
await CheckIsValidContact(contactData.number);
|
||||||
|
|
||||||
const { contactId } = req.params;
|
const { contactId } = req.params;
|
||||||
|
@ -239,13 +233,3 @@ export const contacsBulkInsertOnQueue = async (
|
||||||
|
|
||||||
return res.status(200).json({ message: "ok" });
|
return res.status(200).json({ message: "ok" });
|
||||||
};
|
};
|
||||||
|
|
||||||
function addStartPhoneNumber(phoneNumber: string) {
|
|
||||||
const regex = /^55/;
|
|
||||||
|
|
||||||
if (!regex.test(phoneNumber)) {
|
|
||||||
phoneNumber = "55" + phoneNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
return phoneNumber;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
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";
|
||||||
|
@ -10,17 +9,6 @@ import ShowTicketService from "../services/TicketServices/ShowTicketService";
|
||||||
import DeleteWhatsAppMessage from "../services/WbotServices/DeleteWhatsAppMessage";
|
import DeleteWhatsAppMessage from "../services/WbotServices/DeleteWhatsAppMessage";
|
||||||
import SendWhatsAppMedia from "../services/WbotServices/SendWhatsAppMedia";
|
import SendWhatsAppMedia from "../services/WbotServices/SendWhatsAppMedia";
|
||||||
import SendWhatsAppMessage from "../services/WbotServices/SendWhatsAppMessage";
|
import SendWhatsAppMessage from "../services/WbotServices/SendWhatsAppMessage";
|
||||||
import axios from "axios";
|
|
||||||
import Contact from "../models/Contact";
|
|
||||||
import {
|
|
||||||
isValidMsg,
|
|
||||||
verifyMessage
|
|
||||||
} from "../services/WbotServices/wbotMessageListener";
|
|
||||||
import CreateOrUpdateContactService from "../services/ContactServices/CreateOrUpdateContactService";
|
|
||||||
import sendWhatsAppMessageOfficialAPI from "../helpers/sendWhatsAppMessageOfficialAPI";
|
|
||||||
import Whatsapp from "../models/Whatsapp";
|
|
||||||
import checkLastClientMsg24hs from "../helpers/CheckLastClientMsg24hs";
|
|
||||||
import AppError from "../errors/AppError";
|
|
||||||
|
|
||||||
type IndexQuery = {
|
type IndexQuery = {
|
||||||
pageNumber: string;
|
pageNumber: string;
|
||||||
|
@ -31,8 +19,6 @@ type MessageData = {
|
||||||
fromMe: boolean;
|
fromMe: boolean;
|
||||||
read: boolean;
|
read: boolean;
|
||||||
quotedMsg?: Message;
|
quotedMsg?: Message;
|
||||||
mic_audio?: boolean;
|
|
||||||
params: any;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const index = async (req: Request, res: Response): Promise<Response> => {
|
export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||||
|
@ -44,103 +30,28 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||||
ticketId
|
ticketId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// SetTicketMessagesAsRead(ticket);
|
||||||
|
|
||||||
return res.json({ count, messages, ticket, hasMore });
|
return res.json({ count, messages, ticket, hasMore });
|
||||||
};
|
};
|
||||||
|
|
||||||
export const store = async (req: Request, res: Response): Promise<Response> => {
|
export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
|
|
||||||
const { ticketId } = req.params;
|
const { ticketId } = req.params;
|
||||||
const { body, quotedMsg, mic_audio, params }: MessageData = req.body;
|
const { body, quotedMsg }: MessageData = req.body;
|
||||||
const medias = req.files as Express.Multer.File[];
|
const medias = req.files as Express.Multer.File[];
|
||||||
|
|
||||||
const ticket = await ShowTicketService(ticketId);
|
const ticket = await ShowTicketService(ticketId);
|
||||||
|
|
||||||
const { queueId } = ticket;
|
console.log('TICKET ID: ', ticketId)
|
||||||
console.log(
|
|
||||||
"-----------> queueId: ",
|
|
||||||
queueId,
|
|
||||||
" | quotedMsg: ",
|
|
||||||
quotedMsg,
|
|
||||||
" | params: ",
|
|
||||||
params
|
|
||||||
);
|
|
||||||
|
|
||||||
const { phoneNumberId, whatsappId } = ticket;
|
// SetTicketMessagesAsRead(ticket);
|
||||||
|
|
||||||
if (phoneNumberId) {
|
|
||||||
const into24hs = await checkLastClientMsg24hs(ticket);
|
|
||||||
|
|
||||||
if (into24hs && into24hs.length == 0) {
|
|
||||||
if (params) {
|
|
||||||
console.log("SEND TEMPLATE PARAMS: ", params);
|
|
||||||
|
|
||||||
// return res.send()
|
|
||||||
|
|
||||||
let payloadComponents = [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
for (let i in params) {
|
|
||||||
const { parameters, language, type } = params[i];
|
|
||||||
if (type == "BODY") {
|
|
||||||
if (parameters && parameters.length > 0) {
|
|
||||||
let components: any = [{ type: "body", parameters: [] }];
|
|
||||||
for (let x in parameters) {
|
|
||||||
const { type, text, index } = parameters[x];
|
|
||||||
console.log(text);
|
|
||||||
components[0].parameters.splice(index - 1, 0, {
|
|
||||||
type,
|
|
||||||
text
|
|
||||||
});
|
|
||||||
}
|
|
||||||
payloadComponents.push(components[0]);
|
|
||||||
}
|
|
||||||
} else if (type == "BUTTONS") {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const name = params.find((p: any) => p?.template_name);
|
|
||||||
const { language }: any = params.find((p: any) => p?.language);
|
|
||||||
|
|
||||||
const { template_name } = name;
|
|
||||||
|
|
||||||
if (template_name && language) {
|
|
||||||
const template: any = {
|
|
||||||
template: {
|
|
||||||
name: template_name,
|
|
||||||
language: { code: language },
|
|
||||||
components: payloadComponents
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
sendWhatsAppMessageOfficialAPI(ticket, body, null, template);
|
|
||||||
|
|
||||||
console.log("TEMPLATE: ", template);
|
|
||||||
return res.send();
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
|
||||||
throw new AppError(error.message);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
const { wabaId }: any = await Whatsapp.findByPk(whatsappId);
|
|
||||||
|
|
||||||
const { data } = await whatsappOfficialAPI.get(
|
|
||||||
`/${process.env.VERSION}/${wabaId}/message_templates?language=pt_BR`
|
|
||||||
);
|
|
||||||
|
|
||||||
return res.status(200).json(data);
|
|
||||||
} catch (error) {
|
|
||||||
return res
|
|
||||||
.status(500)
|
|
||||||
.json({ message: "Não foi possível baixar os templates!" });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (medias) {
|
if (medias) {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
medias.map(async (media: Express.Multer.File) => {
|
medias.map(async (media: Express.Multer.File) => {
|
||||||
console.log(
|
|
||||||
`\n >>>>>>>>>> SENDING MESSAGE MEDIA
|
console.log(`\n >>>>>>>>>> SENDING MESSAGE MEDIA
|
||||||
Parcial ticket info and media:
|
Parcial ticket info and media:
|
||||||
ticket.id: ${ticket.id}
|
ticket.id: ${ticket.id}
|
||||||
ticket.status: ${ticket.status}
|
ticket.status: ${ticket.status}
|
||||||
|
@ -150,14 +61,13 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
ticket.contact.profilePicUrl: ${ticket.contact.profilePicUrl}
|
ticket.contact.profilePicUrl: ${ticket.contact.profilePicUrl}
|
||||||
ticket.user.id: ${ticket.user.id}
|
ticket.user.id: ${ticket.user.id}
|
||||||
ticket.user.name: ${ticket.user.name}
|
ticket.user.name: ${ticket.user.name}
|
||||||
media:`,
|
media:`, media,'\n')
|
||||||
media,
|
|
||||||
"\n"
|
await SendWhatsAppMedia({ media, ticket });
|
||||||
);
|
|
||||||
await SendWhatsAppMedia({ media, ticket, mic_audio });
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
console.log(`\n >>>>>>>>>> SENDING MESSAGE
|
console.log(`\n >>>>>>>>>> SENDING MESSAGE
|
||||||
Parcial ticket info:
|
Parcial ticket info:
|
||||||
ticket.id: ${ticket.id}
|
ticket.id: ${ticket.id}
|
||||||
|
@ -168,7 +78,8 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
ticket.contact.name: ${ticket.contact.name}
|
ticket.contact.name: ${ticket.contact.name}
|
||||||
ticket.contact.profilePicUrl: ${ticket.contact.profilePicUrl}
|
ticket.contact.profilePicUrl: ${ticket.contact.profilePicUrl}
|
||||||
ticket.user.id: ${ticket.user.id}
|
ticket.user.id: ${ticket.user.id}
|
||||||
ticket.user.name: ${ticket.user.name}\n`);
|
ticket.user.name: ${ticket.user.name}\n`)
|
||||||
|
|
||||||
|
|
||||||
await SendWhatsAppMessage({ body, ticket, quotedMsg });
|
await SendWhatsAppMessage({ body, ticket, quotedMsg });
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,6 @@ import DeleteQueueService from "../services/QueueService/DeleteQueueService";
|
||||||
import ListQueuesService from "../services/QueueService/ListQueuesService";
|
import ListQueuesService from "../services/QueueService/ListQueuesService";
|
||||||
import ShowQueueService from "../services/QueueService/ShowQueueService";
|
import ShowQueueService from "../services/QueueService/ShowQueueService";
|
||||||
import UpdateQueueService from "../services/QueueService/UpdateQueueService";
|
import UpdateQueueService from "../services/QueueService/UpdateQueueService";
|
||||||
import Queue from "../models/Queue"
|
|
||||||
import AppError from "../errors/AppError"
|
|
||||||
import { get, set } from "../helpers/RedisClient";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -31,106 +28,6 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
return res.status(200).json(queue);
|
return res.status(200).json(queue);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const customization = async (
|
|
||||||
req: Request,
|
|
||||||
res: Response
|
|
||||||
): Promise<Response> => {
|
|
||||||
const { ura } = req.body;
|
|
||||||
|
|
||||||
if (!ura) throw new AppError("BAD REQUEST", 400);
|
|
||||||
|
|
||||||
let new_queues: any;
|
|
||||||
|
|
||||||
if (ura.length > 0) {
|
|
||||||
new_queues = ura
|
|
||||||
.filter(
|
|
||||||
(u: any) =>
|
|
||||||
u.idmaster === ura[1].id &&
|
|
||||||
u?.queueName &&
|
|
||||||
u?.color &&
|
|
||||||
u?.greetingMessage
|
|
||||||
)
|
|
||||||
.map((u: any) => {
|
|
||||||
const { queueName, color, greetingMessage } = u;
|
|
||||||
return {
|
|
||||||
queueName: queueName?.trim()?.replace(/\s+/g, " "),
|
|
||||||
color,
|
|
||||||
greetingMessage
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
if (new_queues && new_queues.length > 0) {
|
|
||||||
const db_queues: any = await Queue.findAll();
|
|
||||||
|
|
||||||
for (const i in new_queues) {
|
|
||||||
let { queueName: name, color, greetingMessage } = new_queues[i];
|
|
||||||
|
|
||||||
name = name?.trim()?.replace(/\s+/g, " ");
|
|
||||||
|
|
||||||
const update = db_queues.find(
|
|
||||||
(q: any) => q.name?.trim()?.replace(/\s+/g, " ") == name
|
|
||||||
);
|
|
||||||
|
|
||||||
if (update) {
|
|
||||||
const { id } = update;
|
|
||||||
// UPDATE
|
|
||||||
// const queue = await UpdateQueueService(id, {
|
|
||||||
// name,
|
|
||||||
// color,
|
|
||||||
// greetingMessage
|
|
||||||
// });
|
|
||||||
|
|
||||||
// const io = getIO();
|
|
||||||
// io.emit("queue", {
|
|
||||||
// action: "update",
|
|
||||||
// queue
|
|
||||||
// });
|
|
||||||
} else {
|
|
||||||
// CREATE
|
|
||||||
// const queue = await CreateQueueService({
|
|
||||||
// name,
|
|
||||||
// color,
|
|
||||||
// greetingMessage
|
|
||||||
// });
|
|
||||||
// const io = getIO();
|
|
||||||
// io.emit("queue", {
|
|
||||||
// action: "update",
|
|
||||||
// queue
|
|
||||||
// });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let remove_queues = db_queues.filter(
|
|
||||||
(q: any) =>
|
|
||||||
!new_queues
|
|
||||||
.map((nq: any) => nq.queueName)
|
|
||||||
.includes(q.name?.trim()?.replace(/\s+/g, " "))
|
|
||||||
);
|
|
||||||
|
|
||||||
for (const i in remove_queues) {
|
|
||||||
const { id, name } = remove_queues[i];
|
|
||||||
|
|
||||||
// await DeleteQueueService(id);
|
|
||||||
|
|
||||||
// const io = getIO();
|
|
||||||
// io.emit("queue", {
|
|
||||||
// action: "delete",
|
|
||||||
// queueId: +id
|
|
||||||
// });
|
|
||||||
}
|
|
||||||
|
|
||||||
// await set("ura", ura);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await set("ura", ura);
|
|
||||||
|
|
||||||
const _ura = await get("ura");
|
|
||||||
console.log("_URA: ", _ura);
|
|
||||||
|
|
||||||
return res.status(200).json({ new_queues });
|
|
||||||
};
|
|
||||||
|
|
||||||
export const show = async (req: Request, res: Response): Promise<Response> => {
|
export const show = async (req: Request, res: Response): Promise<Response> => {
|
||||||
const { queueId } = req.params;
|
const { queueId } = req.params;
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,6 @@ type IndexQuery = {
|
||||||
startDate: string;
|
startDate: string;
|
||||||
endDate: string;
|
endDate: string;
|
||||||
pageNumber: string;
|
pageNumber: string;
|
||||||
userQueues: [];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type ReportOnQueue = {
|
type ReportOnQueue = {
|
||||||
|
@ -45,20 +44,13 @@ type ReportOnQueue = {
|
||||||
|
|
||||||
export const reportUserByDateStartDateEnd = async (req: Request, res: Response): Promise<Response> => {
|
export const reportUserByDateStartDateEnd = async (req: Request, res: Response): Promise<Response> => {
|
||||||
|
|
||||||
if (
|
if (req.user.profile !== "master" && req.user.profile !== "admin") {
|
||||||
req.user.profile !== "master" &&
|
|
||||||
req.user.profile !== "admin" &&
|
|
||||||
req.user.profile !== "supervisor"
|
|
||||||
) {
|
|
||||||
throw new AppError("ERR_NO_PERMISSION", 403);
|
throw new AppError("ERR_NO_PERMISSION", 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { userId, startDate, endDate, pageNumber, userQueues } = req.query as IndexQuery
|
const { userId, startDate, endDate, pageNumber } = req.query as IndexQuery
|
||||||
|
|
||||||
console.log("userId, startDate, endDate, pageNumber: ", userId, startDate, endDate, pageNumber);
|
|
||||||
|
|
||||||
const { tickets, count, hasMore } = await ShowTicketReport({ userId, startDate, endDate, pageNumber });
|
const { tickets, count, hasMore } = await ShowTicketReport({ userId, startDate, endDate, pageNumber });
|
||||||
// console.log('kkkkkkkkkkkkkkkkkk tickets: ', JSON.stringify(tickets, null, 6))
|
|
||||||
|
|
||||||
return res.status(200).json({ tickets, count, hasMore });
|
return res.status(200).json({ tickets, count, hasMore });
|
||||||
};
|
};
|
||||||
|
@ -66,16 +58,13 @@ export const reportUserByDateStartDateEnd = async (req: Request, res: Response):
|
||||||
|
|
||||||
export const reportUserService = async (req: Request, res: Response): Promise<Response> => {
|
export const reportUserService = async (req: Request, res: Response): Promise<Response> => {
|
||||||
|
|
||||||
if (req.user.profile !== "master" && req.user.profile !== "admin" && req.user.profile !=="supervisor") {
|
if (req.user.profile !== "master" && req.user.profile !== "admin") {
|
||||||
throw new AppError("ERR_NO_PERMISSION", 403);
|
throw new AppError("ERR_NO_PERMISSION", 403);
|
||||||
}
|
}
|
||||||
const { userId, startDate, endDate } = req.query as IndexQuery
|
const { userId, startDate, endDate } = req.query as IndexQuery
|
||||||
|
|
||||||
// let usersProfile = await ListUserParamiterService({ profile: 'user' })
|
|
||||||
let usersProfile = await ListUserParamiterService({
|
let usersProfile = await ListUserParamiterService({ profile: 'user', raw:true })
|
||||||
profiles: ["user", "supervisor"],
|
|
||||||
raw: true
|
|
||||||
});
|
|
||||||
|
|
||||||
const sumUserOlineTime = await ShowUserServiceReport({ startDate, endDate, userId });
|
const sumUserOlineTime = await ShowUserServiceReport({ startDate, endDate, userId });
|
||||||
const closedByUser = await ShowUserServiceReport({ startDate, endDate, ticketStatus: 'closed', userId });
|
const closedByUser = await ShowUserServiceReport({ startDate, endDate, ticketStatus: 'closed', userId });
|
||||||
|
@ -195,11 +184,7 @@ export const reportUserService = async (req: Request, res: Response): Promise<Re
|
||||||
|
|
||||||
export const reportMessagesUserByDateStartDateEnd = async (req: Request, res: Response): Promise<Response> => {
|
export const reportMessagesUserByDateStartDateEnd = async (req: Request, res: Response): Promise<Response> => {
|
||||||
|
|
||||||
if (
|
if (req.user.profile !== "master" && req.user.profile !== "admin") {
|
||||||
req.user.profile !== "master" &&
|
|
||||||
req.user.profile !== "admin" &&
|
|
||||||
req.user.profile !== "supervisor"
|
|
||||||
) {
|
|
||||||
throw new AppError("ERR_NO_PERMISSION", 403);
|
throw new AppError("ERR_NO_PERMISSION", 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,6 @@ import AuthUserService from "../services/UserServices/AuthUserService";
|
||||||
import { SendRefreshToken } from "../helpers/SendRefreshToken";
|
import { SendRefreshToken } from "../helpers/SendRefreshToken";
|
||||||
import { RefreshTokenService } from "../services/AuthServices/RefreshTokenService";
|
import { RefreshTokenService } from "../services/AuthServices/RefreshTokenService";
|
||||||
|
|
||||||
import createOrUpdateOnlineUserService from "../services/UserServices/CreateOrUpdateOnlineUserService";
|
|
||||||
import { removeUserFromOlineList } from "../helpers/removeUserFromOnlineList";
|
|
||||||
|
|
||||||
// const usersSocket = require("./../libs/socket");
|
|
||||||
const usersSocket = require("../libs/socket");
|
|
||||||
|
|
||||||
export const store = async (req: Request, res: Response): Promise<Response> => {
|
export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
const { email, password } = req.body;
|
const { email, password } = req.body;
|
||||||
|
|
||||||
|
@ -21,11 +15,6 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
|
|
||||||
SendRefreshToken(res, refreshToken);
|
SendRefreshToken(res, refreshToken);
|
||||||
|
|
||||||
const userOnline = await createOrUpdateOnlineUserService({
|
|
||||||
userId: serializedUser.id,
|
|
||||||
status: "online"
|
|
||||||
});
|
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
token,
|
token,
|
||||||
user: serializedUser
|
user: serializedUser
|
||||||
|
@ -58,14 +47,5 @@ export const remove = async (
|
||||||
): Promise<Response> => {
|
): Promise<Response> => {
|
||||||
res.clearCookie("jrt");
|
res.clearCookie("jrt");
|
||||||
|
|
||||||
const { userId } = req.params;
|
|
||||||
|
|
||||||
removeUserFromOlineList(userId);
|
|
||||||
|
|
||||||
const userOnline = await createOrUpdateOnlineUserService({
|
|
||||||
userId,
|
|
||||||
status: "offline"
|
|
||||||
});
|
|
||||||
|
|
||||||
return res.send();
|
return res.send();
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,8 +8,6 @@ import ListSettingsService from "../services/SettingServices/ListSettingsService
|
||||||
import loadSettings from "../helpers/LoadSettings";
|
import loadSettings from "../helpers/LoadSettings";
|
||||||
import updateSettingTicket from "../services/SettingServices/UpdateSettingTicket";
|
import updateSettingTicket from "../services/SettingServices/UpdateSettingTicket";
|
||||||
import SettingTicket from "../models/SettingTicket";
|
import SettingTicket from "../models/SettingTicket";
|
||||||
import Whatsapp from "../models/Whatsapp";
|
|
||||||
import whatsappOfficialNumberInfo from "../helpers/WhatsappOfficialNumberInfo";
|
|
||||||
|
|
||||||
export const index = async (req: Request, res: Response): Promise<Response> => {
|
export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||||
// if (req.user.profile !== "master") {
|
// if (req.user.profile !== "master") {
|
||||||
|
@ -18,20 +16,9 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||||
|
|
||||||
const settings = await ListSettingsService();
|
const settings = await ListSettingsService();
|
||||||
|
|
||||||
// const config = await SettingTicket.findAll();
|
const config = await SettingTicket.findAll();
|
||||||
|
|
||||||
return res.status(200).json({ settings, });
|
return res.status(200).json({ settings, config });
|
||||||
};
|
|
||||||
|
|
||||||
export const ticketSettings = async (
|
|
||||||
req: Request,
|
|
||||||
res: Response
|
|
||||||
): Promise<Response> => {
|
|
||||||
const { number } = req.params;
|
|
||||||
|
|
||||||
const config = await SettingTicket.findAll({ where: { number } });
|
|
||||||
|
|
||||||
return res.status(200).json({ config });
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateTicketSettings = async (
|
export const updateTicketSettings = async (
|
||||||
|
@ -39,7 +26,6 @@ export const updateTicketSettings = async (
|
||||||
res: Response
|
res: Response
|
||||||
): Promise<Response> => {
|
): Promise<Response> => {
|
||||||
const {
|
const {
|
||||||
number,
|
|
||||||
outBusinessHours,
|
outBusinessHours,
|
||||||
ticketExpiration,
|
ticketExpiration,
|
||||||
weekend,
|
weekend,
|
||||||
|
@ -48,64 +34,58 @@ export const updateTicketSettings = async (
|
||||||
holiday
|
holiday
|
||||||
} = req.body;
|
} = req.body;
|
||||||
|
|
||||||
if (!number) throw new AppError("No number selected", 400);
|
|
||||||
|
|
||||||
if (outBusinessHours && Object.keys(outBusinessHours).length > 0) {
|
if (outBusinessHours && Object.keys(outBusinessHours).length > 0) {
|
||||||
await updateSettingTicket({
|
await updateSettingTicket({
|
||||||
...outBusinessHours,
|
...outBusinessHours,
|
||||||
key: "outBusinessHours",
|
key: "outBusinessHours"
|
||||||
number
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ticketExpiration && Object.keys(ticketExpiration).length > 0) {
|
if (ticketExpiration && Object.keys(ticketExpiration).length > 0) {
|
||||||
await updateSettingTicket({
|
await updateSettingTicket({
|
||||||
...ticketExpiration,
|
...ticketExpiration,
|
||||||
key: "ticketExpiration",
|
key: "ticketExpiration"
|
||||||
number
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (weekend && Object.keys(weekend).length > 0) {
|
if (weekend && Object.keys(weekend).length > 0) {
|
||||||
await updateSettingTicket({
|
await updateSettingTicket({
|
||||||
...weekend,
|
...weekend,
|
||||||
key: "weekend",
|
key: "weekend"
|
||||||
number
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (saturday && Object.keys(saturday).length > 0) {
|
if (saturday && Object.keys(saturday).length > 0) {
|
||||||
await updateSettingTicket({
|
await updateSettingTicket({
|
||||||
...saturday,
|
...saturday,
|
||||||
key: "saturday",
|
key: "saturday"
|
||||||
number
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sunday && Object.keys(sunday).length > 0) {
|
if (sunday && Object.keys(sunday).length > 0) {
|
||||||
await updateSettingTicket({
|
await updateSettingTicket({
|
||||||
...sunday,
|
...sunday,
|
||||||
key: "sunday",
|
key: "sunday"
|
||||||
number
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (holiday && Object.keys(holiday).length > 0) {
|
if (holiday && Object.keys(holiday).length > 0) {
|
||||||
await updateSettingTicket({
|
await updateSettingTicket({
|
||||||
...holiday,
|
...holiday,
|
||||||
key: "holiday",
|
key: "holiday"
|
||||||
number
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.status(200).json({
|
return res
|
||||||
outBusinessHours,
|
.status(200)
|
||||||
ticketExpiration,
|
.json({
|
||||||
weekend,
|
outBusinessHours,
|
||||||
saturday,
|
ticketExpiration,
|
||||||
sunday,
|
weekend,
|
||||||
holiday
|
saturday,
|
||||||
});
|
sunday,
|
||||||
|
holiday
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const update = async (
|
export const update = async (
|
||||||
|
@ -123,40 +103,6 @@ export const update = async (
|
||||||
value
|
value
|
||||||
});
|
});
|
||||||
|
|
||||||
if (key && key == "whatsaAppCloudApi") {
|
|
||||||
let whatsapps: any = await Whatsapp.findAll();
|
|
||||||
|
|
||||||
if (whatsapps) {
|
|
||||||
for (let i in whatsapps) {
|
|
||||||
const { id, wabaId, isOfficial } = whatsapps[i];
|
|
||||||
|
|
||||||
if (isOfficial && wabaId) {
|
|
||||||
try {
|
|
||||||
const whatsapp = await Whatsapp.findByPk(id);
|
|
||||||
if (whatsapp) {
|
|
||||||
if (value == "disabled") {
|
|
||||||
whatsapp.update({ status: "OPENING" });
|
|
||||||
} else if (value == "enabled") {
|
|
||||||
const info = await whatsappOfficialNumberInfo(wabaId);
|
|
||||||
if (info) {
|
|
||||||
whatsapp.update({
|
|
||||||
classification: info.quality_rating,
|
|
||||||
status: "CONNECTED"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log(
|
|
||||||
"error on try update classification number from oficial whatsapp in SettingControllers.ts: ",
|
|
||||||
error
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loadSettings();
|
loadSettings();
|
||||||
|
|
||||||
const io = getIO();
|
const io = getIO();
|
||||||
|
|
|
@ -64,10 +64,6 @@ import Contact from "../models/Contact";
|
||||||
import BotIsOnQueue from "../helpers/BotIsOnQueue";
|
import BotIsOnQueue from "../helpers/BotIsOnQueue";
|
||||||
import { setMessageAsRead } from "../helpers/SetMessageAsRead";
|
import { setMessageAsRead } from "../helpers/SetMessageAsRead";
|
||||||
import { getSettingValue } from "../helpers/WhaticketSettings";
|
import { getSettingValue } from "../helpers/WhaticketSettings";
|
||||||
import ListWhatsAppsForQueueService from "../services/WhatsappService/ListWhatsAppsForQueueService";
|
|
||||||
import ListWhatsAppsNumber from "../services/WhatsappService/ListWhatsAppsNumber";
|
|
||||||
import Whatsapp from "../models/Whatsapp";
|
|
||||||
import AppError from "../errors/AppError";
|
|
||||||
|
|
||||||
export const index = async (req: Request, res: Response): Promise<Response> => {
|
export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||||
const {
|
const {
|
||||||
|
@ -107,45 +103,26 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const store = async (req: Request, res: Response): Promise<Response> => {
|
export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
const { contactId, status, userId, msg, queueId, whatsappId }: TicketData =
|
const { contactId, status, userId, msg, queueId }: TicketData = req.body;
|
||||||
req.body;
|
|
||||||
|
|
||||||
const botInfo = await BotIsOnQueue("botqueue");
|
// const botInfo = await BotIsOnQueue("botqueue");
|
||||||
|
|
||||||
let ticket = await Ticket.findOne({
|
let ticket = await Ticket.findOne({
|
||||||
where: {
|
where: {
|
||||||
[Op.or]: [
|
[Op.or]: [
|
||||||
{ contactId, status: "queueChoice" },
|
{ contactId, status: "queueChoice" }
|
||||||
{ contactId, status: "open", userId: botInfo.userIdBot }
|
// { contactId, status: "open", userId: botInfo.userIdBot }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (getSettingValue("whatsaAppCloudApi")?.value == "enabled") {
|
if (ticket) {
|
||||||
if (ticket) {
|
await UpdateTicketService({
|
||||||
await UpdateTicketService({
|
ticketData: { status: "open", userId: userId, queueId },
|
||||||
ticketData: { status: "closed" },
|
ticketId: ticket.id
|
||||||
ticketId: ticket.id
|
|
||||||
});
|
|
||||||
ticket = null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (ticket) {
|
|
||||||
await UpdateTicketService({
|
|
||||||
ticketData: { status: "open", userId: userId, queueId },
|
|
||||||
ticketId: ticket.id
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ticket) {
|
|
||||||
ticket = await CreateTicketService({
|
|
||||||
contactId,
|
|
||||||
status,
|
|
||||||
userId,
|
|
||||||
queueId,
|
|
||||||
whatsappId
|
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
ticket = await CreateTicketService({ contactId, status, userId, queueId });
|
||||||
}
|
}
|
||||||
|
|
||||||
const io = getIO();
|
const io = getIO();
|
||||||
|
@ -153,6 +130,15 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
action: "update",
|
action: "update",
|
||||||
ticket
|
ticket
|
||||||
});
|
});
|
||||||
|
//
|
||||||
|
|
||||||
|
// const ticket = await CreateTicketService({ contactId, status, userId });
|
||||||
|
|
||||||
|
// const io = getIO();
|
||||||
|
// io.to(ticket.status).emit("ticket", {
|
||||||
|
// action: "update",
|
||||||
|
// ticket
|
||||||
|
// });
|
||||||
|
|
||||||
return res.status(200).json(ticket);
|
return res.status(200).json(ticket);
|
||||||
};
|
};
|
||||||
|
@ -250,6 +236,7 @@ export const update = async (
|
||||||
|
|
||||||
ticket2 = ticket;
|
ticket2 = ticket;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Para aparecer pendente para todos usuarios que estao na fila
|
// Para aparecer pendente para todos usuarios que estao na fila
|
||||||
if (req.body.transfer) {
|
if (req.body.transfer) {
|
||||||
req.body.userId = null;
|
req.body.userId = null;
|
||||||
|
@ -259,82 +246,20 @@ export const update = async (
|
||||||
|
|
||||||
if (getSettingValue("oneContactChatWithManyWhats")?.value == "enabled") {
|
if (getSettingValue("oneContactChatWithManyWhats")?.value == "enabled") {
|
||||||
if (ticketData.transfer) {
|
if (ticketData.transfer) {
|
||||||
const whatsappsByqueue = await ListWhatsAppsForQueueService(
|
const defaultWhatsapp: any = await GetDefaultWhatsApp(
|
||||||
ticketData.queueId
|
ticketData.userId
|
||||||
);
|
);
|
||||||
|
|
||||||
if (userOldInfo) {
|
const _ticket: any = await Ticket.findByPk(ticketId);
|
||||||
let listTicketOpenPending: any = [];
|
|
||||||
|
|
||||||
for (const w of whatsappsByqueue) {
|
if (defaultWhatsapp && ticketData.status != "open") {
|
||||||
let whats = await ListWhatsAppsNumber(w.id);
|
await CheckContactOpenTickets(
|
||||||
|
_ticket.dataValues.contactId,
|
||||||
console.log("-------> WHATS: ", JSON.stringify(whats, null, 6));
|
defaultWhatsapp.dataValues.id
|
||||||
const ticket = await Ticket.findOne({
|
);
|
||||||
where: {
|
|
||||||
[Op.and]: [
|
|
||||||
{ contactId: userOldInfo.contactId },
|
|
||||||
{
|
|
||||||
whatsappId: {
|
|
||||||
[Op.in]: whats.whatsapps.map((w: any) => w.id)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ status: { [Op.or]: ["open", "pending"] } }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (ticket) {
|
|
||||||
listTicketOpenPending.push({
|
|
||||||
ticketId: ticket.id,
|
|
||||||
status: ticket.status,
|
|
||||||
userId: ticket.userId,
|
|
||||||
contactId: ticket.contactId,
|
|
||||||
whatsappId: ticket.whatsappId,
|
|
||||||
queueId: ticket.queueId
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// console.log("userOldInfo: ", JSON.stringify(userOldInfo, null, 6));
|
|
||||||
// console.log("##########")
|
|
||||||
// console.log(
|
|
||||||
// "listTicketOpenPending: ",
|
|
||||||
// JSON.stringify(listTicketOpenPending)
|
|
||||||
// );
|
|
||||||
|
|
||||||
if (
|
|
||||||
listTicketOpenPending.filter(
|
|
||||||
(ob: any) => userOldInfo.whatsappId != ob.whatsappId
|
|
||||||
)?.length > 0
|
|
||||||
) {
|
|
||||||
throw new AppError("ERR_OTHER_OPEN_TICKET");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////
|
ticketData.whatsappId = defaultWhatsapp.dataValues.id;
|
||||||
|
|
||||||
// const defaultWhatsapp: any = await GetDefaultWhatsApp({
|
|
||||||
// userId: ticketData.userId
|
|
||||||
// });
|
|
||||||
|
|
||||||
// console.log(
|
|
||||||
// "ticketData.userId: ",
|
|
||||||
// ticketData.userId,
|
|
||||||
// " | defaultWhatsapp: ",
|
|
||||||
// JSON.stringify(defaultWhatsapp, null, 6)
|
|
||||||
// );
|
|
||||||
|
|
||||||
// const _ticket: any = await Ticket.findByPk(ticketId);
|
|
||||||
|
|
||||||
// if (defaultWhatsapp && ticketData.status != "open") {
|
|
||||||
// await CheckContactOpenTickets(
|
|
||||||
// _ticket.dataValues.contactId,
|
|
||||||
// defaultWhatsapp.dataValues.id
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
// ticketData.whatsappId = defaultWhatsapp.dataValues.id;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,6 +279,8 @@ export const update = async (
|
||||||
await setMessageAsRead(ticket);
|
await setMessageAsRead(ticket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log("ticket.unreadMessages: ", ticket.unreadMessages);
|
||||||
|
|
||||||
if (ticketData.userId) {
|
if (ticketData.userId) {
|
||||||
const dateToday = splitDateTime(
|
const dateToday = 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 }))
|
||||||
|
|
|
@ -10,29 +10,20 @@ import UpdateUserService from "../services/UserServices/UpdateUserService";
|
||||||
import ShowUserService from "../services/UserServices/ShowUserService";
|
import ShowUserService from "../services/UserServices/ShowUserService";
|
||||||
import DeleteUserService from "../services/UserServices/DeleteUserService";
|
import DeleteUserService from "../services/UserServices/DeleteUserService";
|
||||||
|
|
||||||
import ListUser from "../services/UserServices/ListUserParamiterService";
|
import ListUserParamiterService from "../services/UserServices/ListUserParamiterService";
|
||||||
import User from "../models/User";
|
import User from "../models/User";
|
||||||
import { get, set } from "../helpers/RedisClient";
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
startWhoIsOnlineMonitor,
|
startWhoIsOnlineMonitor,
|
||||||
stopWhoIsOnlineMonitor
|
stopWhoIsOnlineMonitor
|
||||||
} from "../helpers/WhoIsOnlineMonitor";
|
} from "../helpers/WhoIsOnlineMonitor";
|
||||||
import UserOnlineTIme from "../models/UserOnlineTime";
|
import UserOnlineTIme from "../models/UserOnlineTime";
|
||||||
|
import ListUser from "../services/UserServices/ListUserParamiterService";
|
||||||
import { format, subMonths } from "date-fns";
|
|
||||||
import { ptBR } from "date-fns/locale";
|
|
||||||
import CountTicketsByUserQueue from "../services/UserServices/CountTicketsByUserQueue";
|
|
||||||
import { splitDateTime } from "../helpers/SplitDateTime";
|
|
||||||
import ListUserByWhatsappQueuesService from "../services/UserServices/ListUserByWhatsappQueuesService";
|
|
||||||
import { json } from "sequelize";
|
|
||||||
import { getSettingValue } from "../helpers/WhaticketSettings";
|
|
||||||
|
|
||||||
type IndexQuery = {
|
type IndexQuery = {
|
||||||
searchParam: string;
|
searchParam: string;
|
||||||
pageNumber: string;
|
pageNumber: string;
|
||||||
profile?: string;
|
profile?: string;
|
||||||
userId: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const index = async (req: Request, res: Response): Promise<Response> => {
|
export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||||
|
@ -47,17 +38,8 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||||
if (req.user.profile !== "master") {
|
if (req.user.profile !== "master") {
|
||||||
let auxUsers: Array<object> = [];
|
let auxUsers: Array<object> = [];
|
||||||
|
|
||||||
// for (var user of users) {
|
|
||||||
// if (user.profile !== 'master') {
|
|
||||||
// auxUsers.push(user)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
for (var user of users) {
|
for (var user of users) {
|
||||||
if (user.profile !== "master") {
|
if (user.profile !== "master") {
|
||||||
if (req.user.profile == "supervisor" && user.profile == "admin")
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auxUsers.push(user);
|
auxUsers.push(user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,70 +70,25 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||||
// return res.json({ users, count, hasMore });
|
// return res.json({ users, count, hasMore });
|
||||||
};
|
};
|
||||||
|
|
||||||
// export const usersByWhatsappQueue = async (req: Request, res: Response): Promise<Response> => {
|
|
||||||
// const { profile } = req.query as IndexQuery;
|
|
||||||
|
|
||||||
// const users = await ListUser({
|
|
||||||
// profile
|
|
||||||
// });
|
|
||||||
|
|
||||||
// return res.json({ users });
|
|
||||||
// };
|
|
||||||
|
|
||||||
export const all = async (req: Request, res: Response): Promise<Response> => {
|
export const all = async (req: Request, res: Response): Promise<Response> => {
|
||||||
const { userId, profile } = req.query as IndexQuery;
|
const { profile } = req.query as IndexQuery;
|
||||||
|
|
||||||
console.log(
|
const users = await ListUser({
|
||||||
"userId: ",
|
profile
|
||||||
userId,
|
});
|
||||||
" | profile: ",
|
|
||||||
profile,
|
|
||||||
' | getSettingValue("queueTransferByWhatsappScope")?.value: ',
|
|
||||||
getSettingValue("queueTransferByWhatsappScope")?.value
|
|
||||||
);
|
|
||||||
|
|
||||||
if (getSettingValue("queueTransferByWhatsappScope")?.value == "enabled") {
|
return res.json({ users });
|
||||||
const obj = await ListUserByWhatsappQueuesService(
|
|
||||||
userId,
|
|
||||||
'"admin", "user", "supervisor"'
|
|
||||||
);
|
|
||||||
|
|
||||||
const usersByWhatsqueue = obj.users;
|
|
||||||
const queues = obj.queues;
|
|
||||||
|
|
||||||
let userIds = usersByWhatsqueue.map((w: any) => w.userId);
|
|
||||||
|
|
||||||
const users = await ListUser({
|
|
||||||
userIds
|
|
||||||
});
|
|
||||||
|
|
||||||
return res.json({ users, queues });
|
|
||||||
} else {
|
|
||||||
const users = await ListUser({
|
|
||||||
profile
|
|
||||||
});
|
|
||||||
return res.json({ users });
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const store = async (req: Request, res: Response): Promise<Response> => {
|
export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
const { email, password, name, profile, positionCompany, queueIds } =
|
const { email, password, name, profile, queueIds } = req.body;
|
||||||
req.body;
|
|
||||||
|
|
||||||
console.log("===========> req.url: ", req.url);
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
req.url === "/user" &&
|
|
||||||
getSettingValue("userCreation")?.value == "disabled" &&
|
|
||||||
req.user.profile == "admin"
|
|
||||||
) {
|
|
||||||
throw new AppError("ERR_NO_PERMISSION", 403);
|
|
||||||
} else if (
|
|
||||||
req.url === "/signup" &&
|
req.url === "/signup" &&
|
||||||
getSettingValue("userCreation")?.value == "disabled"
|
(await CheckSettingsHelper("userCreation")) === "disabled"
|
||||||
) {
|
) {
|
||||||
throw new AppError("ERR_USER_CREATION_DISABLED", 403);
|
throw new AppError("ERR_USER_CREATION_DISABLED", 403);
|
||||||
} else if (req.user.profile !== "master") {
|
} else if (req.url !== "/signup" && req.user.profile !== "master") {
|
||||||
throw new AppError("ERR_NO_PERMISSION", 403);
|
throw new AppError("ERR_NO_PERMISSION", 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,7 +96,6 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
email,
|
email,
|
||||||
password,
|
password,
|
||||||
name,
|
name,
|
||||||
positionCompany,
|
|
||||||
profile,
|
profile,
|
||||||
queueIds
|
queueIds
|
||||||
});
|
});
|
||||||
|
@ -213,89 +149,14 @@ export const update = async (
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response
|
res: Response
|
||||||
): Promise<Response> => {
|
): Promise<Response> => {
|
||||||
if (
|
if (req.user.profile !== "admin" && req.user.profile !== "master") {
|
||||||
req.user.profile !== "admin" &&
|
|
||||||
req.user.profile !== "master" &&
|
|
||||||
req.user.profile !== "supervisor"
|
|
||||||
) {
|
|
||||||
throw new AppError("ERR_NO_PERMISSION", 403);
|
throw new AppError("ERR_NO_PERMISSION", 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { userId } = req.params;
|
const { userId } = req.params;
|
||||||
const userData = req.body;
|
const userData = req.body;
|
||||||
|
|
||||||
const dateToday = splitDateTime(
|
const user = await UpdateUserService({ userData, userId });
|
||||||
new Date(format(new Date(), "yyyy-MM-dd HH:mm:ss", { locale: ptBR }))
|
|
||||||
);
|
|
||||||
|
|
||||||
const currentDate = new Date();
|
|
||||||
const tenMonthsAgo = subMonths(currentDate, 10);
|
|
||||||
const formattedDate = format(tenMonthsAgo, "yyyy-MM-dd");
|
|
||||||
console.log("dateToday.fullDate: ", dateToday.fullDate);
|
|
||||||
console.log("formattedDate 10 months ago: ", formattedDate);
|
|
||||||
|
|
||||||
const openByUserOnQueue: any[] = await CountTicketsByUserQueue({
|
|
||||||
startDate: formattedDate,
|
|
||||||
endDate: dateToday.fullDate,
|
|
||||||
status: "open",
|
|
||||||
clientChatStart: true,
|
|
||||||
userId: userId
|
|
||||||
});
|
|
||||||
|
|
||||||
// console.log('------> openByUserOnQueue: ', openByUserOnQueue)
|
|
||||||
// console.log()
|
|
||||||
// console.log('------> 1 userData.queueIds: ', userData.queueIds)
|
|
||||||
|
|
||||||
let userQueuesAttendance = [];
|
|
||||||
|
|
||||||
if ((openByUserOnQueue && openByUserOnQueue.length) > 0) {
|
|
||||||
userQueuesAttendance = openByUserOnQueue.filter(
|
|
||||||
(e: any) => !userData.queueIds.includes(e.queueId)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (userQueuesAttendance && userQueuesAttendance.length > 0) {
|
|
||||||
const queueInAttendance = userQueuesAttendance.map(e => e.queueId);
|
|
||||||
|
|
||||||
const mergedSet = new Set([...userData.queueIds, ...queueInAttendance]);
|
|
||||||
|
|
||||||
// Convert the Set back to an array
|
|
||||||
userData.queueIds = Array.from(mergedSet);
|
|
||||||
|
|
||||||
// console.log('------> 2 userData.queueIds: ', userData.queueIds)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let user: any = await UpdateUserService({ userData, userId });
|
|
||||||
|
|
||||||
if (user?.name?.trim() == "botqueue") {
|
|
||||||
let botInfo;
|
|
||||||
|
|
||||||
if (
|
|
||||||
user?.queues?.length > 0 &&
|
|
||||||
user.queues[0]?.name?.trim() == "botqueue"
|
|
||||||
) {
|
|
||||||
botInfo = JSON.stringify({
|
|
||||||
userId: user.id,
|
|
||||||
queueId: user.queues[0].id,
|
|
||||||
botIsOnQueue: true
|
|
||||||
});
|
|
||||||
botInfo = JSON.parse(botInfo);
|
|
||||||
|
|
||||||
await set("botInfo", botInfo);
|
|
||||||
} else if (
|
|
||||||
user?.queues?.length == 0 ||
|
|
||||||
user.queues[0]?.name?.trim() != "botqueue"
|
|
||||||
) {
|
|
||||||
botInfo = JSON.stringify({
|
|
||||||
userId: user.id,
|
|
||||||
queueId: 0,
|
|
||||||
botIsOnQueue: false
|
|
||||||
});
|
|
||||||
botInfo = JSON.parse(botInfo);
|
|
||||||
|
|
||||||
await set("botInfo", botInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const io = getIO();
|
const io = getIO();
|
||||||
io.emit("user", {
|
io.emit("user", {
|
||||||
|
@ -303,8 +164,6 @@ export const update = async (
|
||||||
user
|
user
|
||||||
});
|
});
|
||||||
|
|
||||||
user.userQueuesAttendance = userQueuesAttendance;
|
|
||||||
|
|
||||||
return res.status(200).json(user);
|
return res.status(200).json(user);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,102 +4,76 @@ import ShowWhatsAppService from "../services/WhatsappService/ShowWhatsAppService
|
||||||
import { logger } from "../utils/logger";
|
import { logger } from "../utils/logger";
|
||||||
import * as Sentry from "@sentry/node";
|
import * as Sentry from "@sentry/node";
|
||||||
import Whatsapp from "../models/Whatsapp";
|
import Whatsapp from "../models/Whatsapp";
|
||||||
import omnihitDashboardSession from "../helpers/OmnhitDashboardSession";
|
|
||||||
|
|
||||||
// type IndexQuery = {
|
// type IndexQuery = {
|
||||||
// centro_custo: string;
|
// centro_custo: string;
|
||||||
// };
|
// };
|
||||||
|
|
||||||
export const wbotMonitorRemote = async (
|
export const wbotMonitorRemote = async (req: Request, res: Response): Promise<Response> => {
|
||||||
req: Request,
|
|
||||||
res: Response
|
|
||||||
): Promise<Response> => {
|
|
||||||
const { action, whatsappId, reason } = req.body;
|
|
||||||
|
|
||||||
console.log(
|
const { action, whatsappId, reason } = req.body
|
||||||
"action: ",
|
|
||||||
action,
|
|
||||||
" | whatsappId: ",
|
|
||||||
whatsappId,
|
|
||||||
" | reason: ",
|
|
||||||
reason
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log("-----------> ACTION: ", req.body["action"]);
|
console.log('-----------> ACTION: ', req.body['action'])
|
||||||
|
|
||||||
const whatsapp: any = await Whatsapp.findByPk(whatsappId, { raw: true });
|
const whatsapp: any = await Whatsapp.findByPk(whatsappId, { raw: true })
|
||||||
|
|
||||||
|
if (whatsapp) {
|
||||||
|
if (action === 'disconnected') {
|
||||||
|
logger.info(`Disconnected session: ${whatsapp.name}, reason: ${reason}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const io = getIO();
|
||||||
|
io.emit("whatsappSession", {
|
||||||
|
action: "update",
|
||||||
|
session: whatsapp
|
||||||
|
});
|
||||||
|
|
||||||
if (whatsapp) {
|
|
||||||
if (action === "disconnected") {
|
|
||||||
logger.info(`Disconnected session: ${whatsapp.name}, reason: ${reason}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let data: any = {};
|
return res.status(200).json({ "message": "Ok" });
|
||||||
data.whatsapp = { ...whatsapp, DB: process.env.DB_NAME };
|
};
|
||||||
data.action = "update";
|
|
||||||
await omnihitDashboardSession(data);
|
|
||||||
|
|
||||||
|
|
||||||
|
export const wbotMonitorQrcodeRemote = async (req: Request, res: Response): Promise<Response> => {
|
||||||
|
|
||||||
|
const { whatsappId } = req.body
|
||||||
|
|
||||||
|
console.log('-----------> QRCODE MONITOR whatsappId: ', req.body['whatsappId'])
|
||||||
|
|
||||||
|
const whatsapp: any = await Whatsapp.findByPk(whatsappId, { raw: true })
|
||||||
|
// let whatsapp = await ShowWhatsAppService(whatsappId)
|
||||||
|
|
||||||
|
if (whatsapp) {
|
||||||
|
const io = getIO();
|
||||||
|
io.emit("whatsappSession", {
|
||||||
|
action: "update",
|
||||||
|
session: whatsapp
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.status(200).json({ "message": "Ok" });
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export const wbotMonitorQrcodeNumberRead = async (req: Request, res: Response): Promise<Response> => {
|
||||||
|
|
||||||
|
const { number } = req.body
|
||||||
|
|
||||||
|
console.log('-----------> number read: ', number)
|
||||||
|
|
||||||
const io = getIO();
|
const io = getIO();
|
||||||
io.emit("whatsappSession", {
|
io.emit("whatsappSession", {
|
||||||
action: "update",
|
action: "error",
|
||||||
session: whatsapp
|
msg: `Numero lido: ${number} \nEssa sessão de whatsapp foi desconectada porque o numero que esta descrito no nome dessa sessão não corresponde ao numero lido!`
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
return res.status(200).json({ message: "Ok" });
|
return res.status(200).json({ "message": "Ok" });
|
||||||
};
|
};
|
||||||
|
|
||||||
export const wbotMonitorQrcodeRemote = async (
|
|
||||||
req: Request,
|
|
||||||
res: Response
|
|
||||||
): Promise<Response> => {
|
|
||||||
const { whatsappId } = req.body;
|
|
||||||
|
|
||||||
console.log(
|
|
||||||
"-----------> QRCODE MONITOR whatsappId: ",
|
|
||||||
req.body["whatsappId"]
|
|
||||||
);
|
|
||||||
|
|
||||||
const whatsapp: any = await Whatsapp.findByPk(whatsappId, { raw: true });
|
|
||||||
// let whatsapp = await ShowWhatsAppService(whatsappId)
|
|
||||||
|
|
||||||
if (whatsapp) {
|
|
||||||
let data: any = {};
|
|
||||||
data.whatsapp = { ...whatsapp, DB: process.env.DB_NAME };
|
|
||||||
data.action = "update";
|
|
||||||
await omnihitDashboardSession(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (whatsapp) {
|
|
||||||
const io = getIO();
|
|
||||||
io.emit("whatsappSession", {
|
|
||||||
action: "update",
|
|
||||||
session: whatsapp
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.status(200).json({ message: "Ok" });
|
|
||||||
};
|
|
||||||
|
|
||||||
export const wbotMonitorQrcodeNumberRead = async (
|
|
||||||
req: Request,
|
|
||||||
res: Response
|
|
||||||
): Promise<Response> => {
|
|
||||||
const { number } = req.body;
|
|
||||||
|
|
||||||
console.log("-----------> number read: ", number);
|
|
||||||
|
|
||||||
const msg = `Numero lido: ${number} \nEssa sessão de whatsapp foi desconectada porque o numero que esta descrito no nome dessa sessão não corresponde ao numero lido!`;
|
|
||||||
let data: any = {};
|
|
||||||
data.msg = msg;
|
|
||||||
data.action = "error";
|
|
||||||
await omnihitDashboardSession(data);
|
|
||||||
|
|
||||||
const io = getIO();
|
|
||||||
io.emit("whatsappSession", {
|
|
||||||
action: "error",
|
|
||||||
msg: `Numero lido: ${number} \nEssa sessão de whatsapp foi desconectada porque o numero que esta descrito no nome dessa sessão não corresponde ao numero lido!`
|
|
||||||
});
|
|
||||||
|
|
||||||
return res.status(200).json({ message: "Ok" });
|
|
||||||
};
|
|
||||||
|
|
|
@ -14,34 +14,13 @@ import UpdateWhatsAppService from "../services/WhatsappService/UpdateWhatsAppSer
|
||||||
import AppError from "../errors/AppError";
|
import AppError from "../errors/AppError";
|
||||||
|
|
||||||
import getNumberFromName from "../helpers/GetNumberSequence";
|
import getNumberFromName from "../helpers/GetNumberSequence";
|
||||||
import phoneNumberStart from "../helpers/PhoneNumberStatusCode";
|
import phoneNumberStart from "../helpers/PhoneNumberStatusCode"
|
||||||
|
|
||||||
import path, { join } from "path";
|
import path from 'path';
|
||||||
import validatePhoneName from "../helpers/ValidatePhoneName";
|
import validatePhoneName from "../helpers/ValidatePhoneName";
|
||||||
import postData from "../helpers/AxiosPost";
|
import postData from "../helpers/AxiosPost";
|
||||||
import Whatsapp from "../models/Whatsapp";
|
import Whatsapp from "../models/Whatsapp";
|
||||||
import Message from "../models/Message";
|
|
||||||
import FindOrCreateTicketService from "../services/TicketServices/FindOrCreateTicketService";
|
|
||||||
import {
|
|
||||||
handleMessage,
|
|
||||||
handleMsgAck,
|
|
||||||
verifyContact,
|
|
||||||
verifyMessage
|
|
||||||
} from "../services/WbotServices/wbotMessageListener";
|
|
||||||
import Contact from "../models/Contact";
|
|
||||||
import CreateOrUpdateContactService from "../services/ContactServices/CreateOrUpdateContactService";
|
|
||||||
import GetDefaultWhatsApp from "../helpers/GetDefaultWhatsApp";
|
|
||||||
import ShowUserService from "../services/UserServices/ShowUserService";
|
|
||||||
|
|
||||||
import fs from "fs";
|
|
||||||
import receiveWhatsAppMediaOfficialAPI from "../helpers/ReceiveWhatsAppMediaOfficialAPI";
|
|
||||||
|
|
||||||
import whatsappOfficialAPI from "../helpers/WhatsappOfficialAPI";
|
|
||||||
import whatsappOfficialNumberInfo from "../helpers/WhatsappOfficialNumberInfo";
|
|
||||||
import { getSettingValue } from "../helpers/WhaticketSettings";
|
|
||||||
import ListWhatsAppsNumber from "../services/WhatsappService/ListWhatsAppsNumber";
|
|
||||||
import SettingTicket from "../models/SettingTicket";
|
|
||||||
import { Op } from "sequelize";
|
|
||||||
|
|
||||||
interface WhatsappData {
|
interface WhatsappData {
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -52,266 +31,16 @@ interface WhatsappData {
|
||||||
farewellMessage?: string;
|
farewellMessage?: string;
|
||||||
status?: string;
|
status?: string;
|
||||||
isDefault?: boolean;
|
isDefault?: boolean;
|
||||||
isOfficial?: boolean;
|
|
||||||
phoneNumberId?: string;
|
|
||||||
wabaId?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let count: number = 0;
|
|
||||||
|
|
||||||
export const index = async (req: Request, res: Response): Promise<Response> => {
|
export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||||
let whatsapps = await ListWhatsAppsService();
|
const whatsapps = await ListWhatsAppsService();
|
||||||
|
|
||||||
if (getSettingValue("whatsaAppCloudApi")?.value == "enabled") {
|
|
||||||
// Atualizar isso quando tiver tempo
|
|
||||||
if (count > 12) count = 0;
|
|
||||||
if (count == 0) {
|
|
||||||
for (let i in whatsapps) {
|
|
||||||
const { id, wabaId, isOfficial } = whatsapps[i];
|
|
||||||
|
|
||||||
if (isOfficial && wabaId) {
|
|
||||||
try {
|
|
||||||
const info = await whatsappOfficialNumberInfo(wabaId);
|
|
||||||
if (info) {
|
|
||||||
const whatsapp = await Whatsapp.findByPk(id);
|
|
||||||
|
|
||||||
if (whatsapp) {
|
|
||||||
whatsapp.update({
|
|
||||||
classification: info.quality_rating
|
|
||||||
});
|
|
||||||
whatsapps[i].classification = info.quality_rating;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log(
|
|
||||||
"error on try update classification number from oficial whatsapp in WhatsappController.ts: ",
|
|
||||||
error
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.log("count: ", count);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.status(200).json(whatsapps);
|
return res.status(200).json(whatsapps);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const whatsAppOfficialMatchQueue = async (
|
|
||||||
req: Request,
|
|
||||||
res: Response
|
|
||||||
): Promise<Response> => {
|
|
||||||
const { userId, queueId }: any = req.query;
|
|
||||||
|
|
||||||
let whatsapps = await GetDefaultWhatsApp({ userId, queueId });
|
|
||||||
|
|
||||||
if (whatsapps && Array.isArray(whatsapps)) {
|
|
||||||
const uniqueWhatsApps = whatsapps.filter(
|
|
||||||
(whatsapp, index, self) =>
|
|
||||||
index === self.findIndex(w => w.number === whatsapp.number)
|
|
||||||
);
|
|
||||||
whatsapps = uniqueWhatsApps;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.status(200).json(whatsapps);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const whatsAppOfficialMatchQueueUser = async (
|
|
||||||
req: Request,
|
|
||||||
res: Response
|
|
||||||
): Promise<Response> => {
|
|
||||||
const { userId, queueId }: any = req.query;
|
|
||||||
|
|
||||||
let whatsApps: any = await ListWhatsAppsService();
|
|
||||||
let user: any = await ShowUserService(userId);
|
|
||||||
|
|
||||||
// console.log(JSON.stringify(user, null, 2));
|
|
||||||
|
|
||||||
let queuesConnected = whatsApps
|
|
||||||
.filter((w: any) => w.status === "CONNECTED")
|
|
||||||
.map((item: any) => {
|
|
||||||
const { queues } = item;
|
|
||||||
return {
|
|
||||||
queues: queues.map((q: any) => {
|
|
||||||
return { id: q.id };
|
|
||||||
})
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.flatMap((item: any) => item.queues.map((queue: any) => queue.id));
|
|
||||||
|
|
||||||
queuesConnected = [...new Set(queuesConnected)].map(q => {
|
|
||||||
return { id: q };
|
|
||||||
});
|
|
||||||
|
|
||||||
const userQueues = user.queues.map((item: any) => {
|
|
||||||
const { id, name, color } = item;
|
|
||||||
return {
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
color,
|
|
||||||
disable: queuesConnected.find((queue: any) => queue.id === id)
|
|
||||||
? false
|
|
||||||
: true
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return res.status(200).json(userQueues);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const media = async (req: Request, res: Response) => {
|
|
||||||
const { filename } = req.params;
|
|
||||||
|
|
||||||
const filePath = join(__dirname, "..", "..", "..", "..", "public", filename);
|
|
||||||
|
|
||||||
console.log("filePath: ", filePath);
|
|
||||||
|
|
||||||
console.log(filename);
|
|
||||||
|
|
||||||
if (!fs.existsSync(filePath)) {
|
|
||||||
return res.status(404).json({ message: "File not folund!" });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set appropriate headers for the download.
|
|
||||||
res.setHeader("Content-Disposition", `attachment; filename=${filename}`);
|
|
||||||
res.sendFile(filePath);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const weebhook = async (
|
|
||||||
req: Request,
|
|
||||||
res: Response
|
|
||||||
): Promise<Response> => {
|
|
||||||
// console.log(JSON.stringify(req.body, null, 2));
|
|
||||||
|
|
||||||
console.log("req.method: ", req.method);
|
|
||||||
|
|
||||||
if (req.method == "GET") {
|
|
||||||
/**
|
|
||||||
* UPDATE YOUR VERIFY TOKEN
|
|
||||||
*This will be the Verify Token value when you set up webhook
|
|
||||||
**/
|
|
||||||
const verify_token = process.env.VERIFY_TOKEN;
|
|
||||||
|
|
||||||
// Parse params from the webhook verification request
|
|
||||||
let mode = req.query["hub.mode"];
|
|
||||||
let token = req.query["hub.verify_token"];
|
|
||||||
let challenge = req.query["hub.challenge"];
|
|
||||||
|
|
||||||
// Check if a token and mode were sent
|
|
||||||
if (mode && token) {
|
|
||||||
// Check the mode and token sent are correct
|
|
||||||
if (mode === "subscribe" && token === verify_token) {
|
|
||||||
// Respond with 200 OK and challenge token from the request
|
|
||||||
console.log("WEBHOOK_VERIFIED");
|
|
||||||
return res.status(200).send(challenge);
|
|
||||||
} else {
|
|
||||||
// Responds with '403 Forbidden' if verify tokens do not match
|
|
||||||
return res.sendStatus(403);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.sendStatus(500);
|
|
||||||
}
|
|
||||||
|
|
||||||
// MESSAGE
|
|
||||||
if (req.body.object) {
|
|
||||||
if (
|
|
||||||
req.body.entry &&
|
|
||||||
req.body.entry[0].changes &&
|
|
||||||
req.body.entry[0].changes[0] &&
|
|
||||||
req.body.entry[0].changes[0].value.messages &&
|
|
||||||
req.body.entry[0].changes[0].value.messages[0]
|
|
||||||
) {
|
|
||||||
const message = req.body.entry[0].changes[0].value.messages[0];
|
|
||||||
const contact_from = message.from; // extract the phone number from the webhook payload
|
|
||||||
const contact_to =
|
|
||||||
req.body.entry[0].changes[0].value.metadata.display_phone_number;
|
|
||||||
let type = message.type;
|
|
||||||
|
|
||||||
let wbot = {};
|
|
||||||
let msg = {};
|
|
||||||
let contacts = req.body.entry[0].changes[0].value.contacts[0];
|
|
||||||
|
|
||||||
msg = {
|
|
||||||
...msg,
|
|
||||||
id: { id: message.id },
|
|
||||||
fromMe: false,
|
|
||||||
type: type,
|
|
||||||
read: false,
|
|
||||||
hasMedia: false
|
|
||||||
};
|
|
||||||
|
|
||||||
// NEW
|
|
||||||
const whatsapp = await ShowWhatsAppService(null, {
|
|
||||||
number: contact_to
|
|
||||||
});
|
|
||||||
|
|
||||||
if (type == "text") {
|
|
||||||
type = "chat";
|
|
||||||
msg = {
|
|
||||||
...msg,
|
|
||||||
body: message.text.body, // extract the message text from the webhook payload,
|
|
||||||
type
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
const mediaId = message[message.type].id;
|
|
||||||
const mimetype = message[message.type].mime_type;
|
|
||||||
|
|
||||||
let filename = await receiveWhatsAppMediaOfficialAPI(
|
|
||||||
mediaId,
|
|
||||||
whatsapp.phoneNumberId
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!filename) throw new AppError("There was an error");
|
|
||||||
|
|
||||||
msg = {
|
|
||||||
...msg,
|
|
||||||
hasMedia: true
|
|
||||||
};
|
|
||||||
|
|
||||||
wbot = { ...wbot, media: { filename, mimetype } };
|
|
||||||
}
|
|
||||||
|
|
||||||
msg = { ...msg, phoneNumberId: whatsapp.phoneNumberId };
|
|
||||||
|
|
||||||
console.log("from: ", contact_from);
|
|
||||||
console.log("to: ", contact_to);
|
|
||||||
console.log("msg type: ", type);
|
|
||||||
|
|
||||||
wbot = {
|
|
||||||
...wbot,
|
|
||||||
id: whatsapp.id,
|
|
||||||
msgContact: {
|
|
||||||
number: contact_from,
|
|
||||||
name: contacts?.profile?.name
|
|
||||||
},
|
|
||||||
chat: { isGroup: false, unreadCount: 1 },
|
|
||||||
quotedMsg: message && message?.context ? message.context.id : undefined
|
|
||||||
};
|
|
||||||
|
|
||||||
handleMessage(msg, wbot, true);
|
|
||||||
|
|
||||||
return res.sendStatus(200);
|
|
||||||
}
|
|
||||||
// STATUS MESSAGE SENT
|
|
||||||
else if (
|
|
||||||
req.body.entry &&
|
|
||||||
req.body.entry[0].changes &&
|
|
||||||
req.body.entry[0].changes[0] &&
|
|
||||||
req.body.entry[0].changes[0].value.statuses &&
|
|
||||||
req.body.entry[0].changes[0].value.statuses[0]
|
|
||||||
) {
|
|
||||||
const id = req.body.entry[0].changes[0].value.statuses[0].id;
|
|
||||||
const ack = req.body.entry[0].changes[0].value.statuses[0].status;
|
|
||||||
handleMsgAck(id, ack, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.sendStatus(200);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const store = async (req: Request, res: Response): Promise<Response> => {
|
export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
let {
|
const {
|
||||||
name,
|
name,
|
||||||
status,
|
status,
|
||||||
isDefault,
|
isDefault,
|
||||||
|
@ -319,39 +48,31 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
farewellMessage,
|
farewellMessage,
|
||||||
queueIds,
|
queueIds,
|
||||||
url,
|
url,
|
||||||
urlApi,
|
urlApi
|
||||||
phoneNumberId,
|
|
||||||
wabaId,
|
|
||||||
isOfficial
|
|
||||||
}: WhatsappData = req.body;
|
}: WhatsappData = req.body;
|
||||||
|
|
||||||
|
// console.log( name,
|
||||||
|
// status,
|
||||||
|
// isDefault,
|
||||||
|
// greetingMessage,
|
||||||
|
// farewellMessage,
|
||||||
|
// queueIds,
|
||||||
|
// url,
|
||||||
|
// urlApi)
|
||||||
|
|
||||||
|
// console.log('getNumberFromName: ', getNumberFromName(name))
|
||||||
|
|
||||||
|
// return res.status(200);
|
||||||
|
|
||||||
|
|
||||||
if (req.user.profile !== "master") {
|
if (req.user.profile !== "master") {
|
||||||
throw new AppError("ERR_NO_PERMISSION", 403);
|
throw new AppError("ERR_NO_PERMISSION", 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
const invalid = checkWhatsAppData({
|
let validate = validatePhoneName(name)
|
||||||
urlApi,
|
|
||||||
isOfficial,
|
|
||||||
phoneNumberId,
|
|
||||||
wabaId
|
|
||||||
});
|
|
||||||
|
|
||||||
if (invalid) {
|
if (validate) {
|
||||||
return res.status(400).json(invalid);
|
return res.status(200).json({ message: validate });
|
||||||
}
|
|
||||||
|
|
||||||
if (isOfficial) {
|
|
||||||
urlApi = "";
|
|
||||||
url = "";
|
|
||||||
} else if (!isOfficial) {
|
|
||||||
phoneNumberId = "";
|
|
||||||
wabaId = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
let invalidPhoneName = validatePhoneName(name);
|
|
||||||
|
|
||||||
if (invalidPhoneName) {
|
|
||||||
return res.status(200).json({ message: invalidPhoneName });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const { whatsapp, oldDefaultWhatsapp } = await CreateWhatsAppService({
|
const { whatsapp, oldDefaultWhatsapp } = await CreateWhatsAppService({
|
||||||
|
@ -362,22 +83,19 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
isDefault,
|
isDefault,
|
||||||
greetingMessage,
|
greetingMessage,
|
||||||
farewellMessage,
|
farewellMessage,
|
||||||
queueIds,
|
queueIds
|
||||||
phoneNumberId,
|
|
||||||
wabaId,
|
|
||||||
isOfficial
|
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("whatsapp.id: ", whatsapp.id);
|
console.log('whatsapp.id: ', whatsapp.id)
|
||||||
|
|
||||||
if (!isOfficial) {
|
postData( `${whatsapp.urlApi}/api/session`, {
|
||||||
postData(`${whatsapp.urlApi}/api/session`, {
|
"app_name": process.env.APP_NAME,
|
||||||
app_name: process.env.APP_NAME,
|
"whatsappId": whatsapp.id,
|
||||||
whatsappId: whatsapp.id,
|
"number": getNumberFromName(name),
|
||||||
number: getNumberFromName(name),
|
"client_url": `${process.env.BACKEND_URL_RAW}:${process.env.PORT}`
|
||||||
client_url: `${process.env.BACKEND_URL_RAW}:${process.env.PORT}`
|
})
|
||||||
});
|
|
||||||
}
|
// StartWhatsAppSession(whatsapp);
|
||||||
|
|
||||||
const io = getIO();
|
const io = getIO();
|
||||||
io.emit("whatsapp", {
|
io.emit("whatsapp", {
|
||||||
|
@ -410,31 +128,13 @@ export const update = async (
|
||||||
const { whatsappId } = req.params;
|
const { whatsappId } = req.params;
|
||||||
const whatsappData = req.body;
|
const whatsappData = req.body;
|
||||||
|
|
||||||
let invalidPhoneName = validatePhoneName(whatsappData.name);
|
|
||||||
|
|
||||||
if (invalidPhoneName) {
|
let validate = validatePhoneName(whatsappData.name)
|
||||||
return res.status(200).json({ message: invalidPhoneName });
|
|
||||||
}
|
|
||||||
|
|
||||||
const { urlApi, isOfficial, phoneNumberId, wabaId } = whatsappData;
|
console.log('validate', validate)
|
||||||
|
|
||||||
const invalid = checkWhatsAppData({
|
if (validate) {
|
||||||
urlApi,
|
return res.status(200).json({ message: validate });
|
||||||
isOfficial,
|
|
||||||
phoneNumberId,
|
|
||||||
wabaId
|
|
||||||
});
|
|
||||||
|
|
||||||
if (invalid) {
|
|
||||||
return res.status(400).json(invalid);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isOfficial) {
|
|
||||||
whatsappData.urlApi = "";
|
|
||||||
whatsappData.url = "";
|
|
||||||
} else if (!isOfficial) {
|
|
||||||
whatsappData.phoneNumberId = "";
|
|
||||||
whatsappData.wabaId = "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const { whatsapp, oldDefaultWhatsapp } = await UpdateWhatsAppService({
|
const { whatsapp, oldDefaultWhatsapp } = await UpdateWhatsAppService({
|
||||||
|
@ -442,14 +142,13 @@ export const update = async (
|
||||||
whatsappId
|
whatsappId
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!whatsappData?.isOfficial) {
|
|
||||||
postData(`${whatsapp.urlApi}/api/session`, {
|
postData( `${whatsapp.urlApi}/api/session`, {
|
||||||
app_name: process.env.APP_NAME,
|
"app_name": process.env.APP_NAME,
|
||||||
whatsappId: whatsapp.id,
|
"whatsappId": whatsapp.id,
|
||||||
number: getNumberFromName(whatsapp.name),
|
"number": getNumberFromName(whatsapp.name),
|
||||||
client_url: `${process.env.BACKEND_URL_RAW}:${process.env.PORT}`
|
"client_url": `${process.env.BACKEND_URL_RAW}:${process.env.PORT}`
|
||||||
});
|
})
|
||||||
}
|
|
||||||
|
|
||||||
const io = getIO();
|
const io = getIO();
|
||||||
io.emit("whatsapp", {
|
io.emit("whatsapp", {
|
||||||
|
@ -471,67 +170,26 @@ export const remove = async (
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response
|
res: Response
|
||||||
): Promise<Response> => {
|
): Promise<Response> => {
|
||||||
|
|
||||||
if (req.user.profile !== "master") {
|
if (req.user.profile !== "master") {
|
||||||
throw new AppError("ERR_NO_PERMISSION", 403);
|
throw new AppError("ERR_NO_PERMISSION", 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { whatsappId } = req.params;
|
const { whatsappId } = req.params;
|
||||||
|
|
||||||
const whatsapp: any = await Whatsapp.findByPk(whatsappId, { raw: true });
|
const whatsapp: any = await Whatsapp.findByPk(whatsappId, { raw: true })
|
||||||
|
|
||||||
if (!whatsapp?.isOfficial) {
|
postData( `${whatsapp.urlApi}/api/session/del`, {
|
||||||
postData(`${whatsapp.urlApi}/api/session/del`, {
|
"app_name": process.env.APP_NAME,
|
||||||
app_name: process.env.APP_NAME,
|
"whatsappId": whatsappId
|
||||||
whatsappId: whatsappId
|
})
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let whats = await ListWhatsAppsNumber(whatsappId);
|
|
||||||
|
|
||||||
// Remove tickets business hours config
|
|
||||||
if (whats?.whatsapps?.length == 1) {
|
|
||||||
const configIds = await SettingTicket.findAll({
|
|
||||||
where: { number: whats?.whatsapps[0]?.number },
|
|
||||||
raw: true,
|
|
||||||
attributes: ["id"]
|
|
||||||
});
|
|
||||||
|
|
||||||
const whatsappTicketConfig = await SettingTicket.findOne({
|
|
||||||
where: { number: whats.whatsapps[0].number }
|
|
||||||
});
|
|
||||||
|
|
||||||
if (whatsappTicketConfig) {
|
|
||||||
try {
|
|
||||||
await SettingTicket.destroy({
|
|
||||||
where: {
|
|
||||||
id: {
|
|
||||||
[Op.in]: configIds.map(config => config.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.log(
|
|
||||||
"Error on delete SettingTicket by number: ",
|
|
||||||
whats?.whatsapps[0]?.number
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await DeleteWhatsAppService(whatsappId);
|
await DeleteWhatsAppService(whatsappId);
|
||||||
|
|
||||||
removeDir(
|
removeDir(path.join(process.cwd(), '.wwebjs_auth', `session-bd_${whatsappId}`))
|
||||||
path.join(process.cwd(), ".wwebjs_auth", `session-bd_${whatsappId}`)
|
|
||||||
);
|
removeDir(path.join(process.cwd(), '.wwebjs_auth', 'sessions', `session-bd_${whatsappId}`))
|
||||||
|
|
||||||
removeDir(
|
|
||||||
path.join(
|
|
||||||
process.cwd(),
|
|
||||||
".wwebjs_auth",
|
|
||||||
"sessions",
|
|
||||||
`session-bd_${whatsappId}`
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
removeWbot(+whatsappId);
|
removeWbot(+whatsappId);
|
||||||
|
|
||||||
|
@ -543,25 +201,3 @@ export const remove = async (
|
||||||
|
|
||||||
return res.status(200).json({ message: "Whatsapp deleted." });
|
return res.status(200).json({ message: "Whatsapp deleted." });
|
||||||
};
|
};
|
||||||
|
|
||||||
interface WhatsappDataValidate {
|
|
||||||
urlApi?: string;
|
|
||||||
isOfficial?: boolean;
|
|
||||||
phoneNumberId?: string;
|
|
||||||
wabaId?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const checkWhatsAppData = ({
|
|
||||||
urlApi,
|
|
||||||
isOfficial,
|
|
||||||
phoneNumberId,
|
|
||||||
wabaId
|
|
||||||
}: WhatsappDataValidate) => {
|
|
||||||
if (isOfficial && (!phoneNumberId || phoneNumberId.trim() == "")) {
|
|
||||||
return { message: "Phone number Id is required!" };
|
|
||||||
} else if (isOfficial && (!wabaId || wabaId.trim() == "")) {
|
|
||||||
return { message: "WABA ID is required!" };
|
|
||||||
} else if (!isOfficial && (!urlApi || urlApi.trim() == "")) {
|
|
||||||
return { message: "urlApi is required!" };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
import { QueryInterface, DataTypes } from "sequelize";
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
up: (queryInterface: QueryInterface) => {
|
|
||||||
return queryInterface.addColumn("Whatsapps", "phoneNumberId", {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: true,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
down: (queryInterface: QueryInterface) => {
|
|
||||||
return queryInterface.removeColumn("Whatsapps", "phoneNumberId");
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,14 +0,0 @@
|
||||||
import { QueryInterface, DataTypes } from "sequelize";
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
up: (queryInterface: QueryInterface) => {
|
|
||||||
return queryInterface.addColumn("Tickets", "phoneNumberId", {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: true
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
down: (queryInterface: QueryInterface) => {
|
|
||||||
return queryInterface.removeColumn("Tickets", "phoneNumberId");
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,14 +0,0 @@
|
||||||
import { QueryInterface, DataTypes } from "sequelize";
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
up: (queryInterface: QueryInterface) => {
|
|
||||||
return queryInterface.addColumn("Messages", "phoneNumberId", {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: true
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
down: (queryInterface: QueryInterface) => {
|
|
||||||
return queryInterface.removeColumn("Messages", "phoneNumberId");
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,15 +0,0 @@
|
||||||
import { QueryInterface, DataTypes } from "sequelize";
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
up: (queryInterface: QueryInterface) => {
|
|
||||||
return queryInterface.addColumn("Whatsapps", "isOfficial", {
|
|
||||||
type: DataTypes.BOOLEAN,
|
|
||||||
allowNull: false,
|
|
||||||
defaultValue: false
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
down: (queryInterface: QueryInterface) => {
|
|
||||||
return queryInterface.removeColumn("Whatsapps", "isOfficial");
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,14 +0,0 @@
|
||||||
import { QueryInterface, DataTypes } from "sequelize";
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
up: (queryInterface: QueryInterface) => {
|
|
||||||
return queryInterface.addColumn("Whatsapps", "wabaId", {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: true
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
down: (queryInterface: QueryInterface) => {
|
|
||||||
return queryInterface.removeColumn("Whatsapps", "wabaId");
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -2,13 +2,16 @@ import { QueryInterface, DataTypes } from "sequelize";
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
up: (queryInterface: QueryInterface) => {
|
up: (queryInterface: QueryInterface) => {
|
||||||
return queryInterface.addColumn("Whatsapps", "classification", {
|
return queryInterface.changeColumn("SettingTickets", "message", {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING(3000),
|
||||||
allowNull: true
|
allowNull: true
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
down: (queryInterface: QueryInterface) => {
|
down: (queryInterface: QueryInterface) => {
|
||||||
return queryInterface.removeColumn("Whatsapps", "classification");
|
return queryInterface.changeColumn("SettingTickets", "message", {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
|
@ -1,14 +0,0 @@
|
||||||
import { QueryInterface, DataTypes } from "sequelize";
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
up: (queryInterface: QueryInterface) => {
|
|
||||||
return queryInterface.addColumn("SettingTickets", "number", {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: true
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
down: (queryInterface: QueryInterface) => {
|
|
||||||
return queryInterface.removeColumn("SettingTickets", "number");
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,14 +0,0 @@
|
||||||
import { QueryInterface, DataTypes } from "sequelize";
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
up: (queryInterface: QueryInterface) => {
|
|
||||||
return queryInterface.addColumn("Users", "positionCompany", {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: true
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
down: (queryInterface: QueryInterface) => {
|
|
||||||
return queryInterface.removeColumn("Users", "positionCompany");
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,26 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
up: (queryInterface, Sequelize) => {
|
|
||||||
/*
|
|
||||||
Add altering commands here.
|
|
||||||
Return a promise to correctly handle asynchronicity.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
return queryInterface.bulkInsert('People', [{
|
|
||||||
name: 'John Doe',
|
|
||||||
isBetaMember: false
|
|
||||||
}], {});
|
|
||||||
*/
|
|
||||||
},
|
|
||||||
|
|
||||||
down: (queryInterface, Sequelize) => {
|
|
||||||
/*
|
|
||||||
Add reverting commands here.
|
|
||||||
Return a promise to correctly handle asynchronicity.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
return queryInterface.bulkDelete('People', null, {});
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,22 +0,0 @@
|
||||||
import { QueryInterface } from "sequelize";
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
up: (queryInterface: QueryInterface) => {
|
|
||||||
return queryInterface.bulkInsert(
|
|
||||||
"Settings",
|
|
||||||
[
|
|
||||||
{
|
|
||||||
key: "whatsaAppCloudApi",
|
|
||||||
value: "disabled",
|
|
||||||
createdAt: new Date(),
|
|
||||||
updatedAt: new Date()
|
|
||||||
}
|
|
||||||
],
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
down: (queryInterface: QueryInterface) => {
|
|
||||||
return queryInterface.bulkDelete("Settings", {});
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,22 +0,0 @@
|
||||||
import { QueryInterface } from "sequelize";
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
up: (queryInterface: QueryInterface) => {
|
|
||||||
return queryInterface.bulkInsert(
|
|
||||||
"Settings",
|
|
||||||
[
|
|
||||||
{
|
|
||||||
key: "queueTransferByWhatsappScope",
|
|
||||||
value: "disabled",
|
|
||||||
createdAt: new Date(),
|
|
||||||
updatedAt: new Date()
|
|
||||||
}
|
|
||||||
],
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
down: (queryInterface: QueryInterface) => {
|
|
||||||
return queryInterface.bulkDelete("Settings", {});
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,22 +0,0 @@
|
||||||
import { QueryInterface } from "sequelize";
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
up: (queryInterface: QueryInterface) => {
|
|
||||||
return queryInterface.bulkInsert(
|
|
||||||
"Settings",
|
|
||||||
[
|
|
||||||
{
|
|
||||||
key: "hasCampaign",
|
|
||||||
value: "disabled",
|
|
||||||
createdAt: new Date(),
|
|
||||||
updatedAt: new Date()
|
|
||||||
}
|
|
||||||
],
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
down: (queryInterface: QueryInterface) => {
|
|
||||||
return queryInterface.bulkDelete("Settings", {});
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -12,7 +12,6 @@ import {
|
||||||
|
|
||||||
import ptBR from "date-fns/locale/pt-BR";
|
import ptBR from "date-fns/locale/pt-BR";
|
||||||
import { splitDateTime } from "./SplitDateTime";
|
import { splitDateTime } from "./SplitDateTime";
|
||||||
import Whatsapp from "../models/Whatsapp";
|
|
||||||
|
|
||||||
const fsPromises = require("fs/promises");
|
const fsPromises = require("fs/promises");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
|
@ -25,43 +24,37 @@ const AutoCloseTickets = async () => {
|
||||||
|
|
||||||
// if (!botInfo.userIdBot) return
|
// if (!botInfo.userIdBot) return
|
||||||
|
|
||||||
const whatsapps = await Whatsapp.findAll({ group: ["number"] });
|
const ticketExpiration = await SettingTicket.findOne({
|
||||||
|
where: { key: "ticketExpiration" }
|
||||||
|
});
|
||||||
|
|
||||||
for (const whatsapp of whatsapps) {
|
if (ticketExpiration && ticketExpiration.value == "enabled") {
|
||||||
// console.log("-------> whatsapp: ", JSON.stringify(whatsapps, null, 6));
|
const startTime = splitDateTime(
|
||||||
|
new Date(
|
||||||
|
_format(new Date(ticketExpiration.startTime), "yyyy-MM-dd HH:mm:ss", {
|
||||||
|
locale: ptBR
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
const ticketExpiration = await SettingTicket.findOne({
|
const seconds = timeStringToSeconds(startTime.fullTime);
|
||||||
where: { key: "ticketExpiration", number: whatsapp.number }
|
|
||||||
|
// console.log("Ticket seconds: ", seconds);
|
||||||
|
|
||||||
|
let tickets: any = await ListTicketTimeLife({
|
||||||
|
timeseconds: seconds,
|
||||||
|
status: "open"
|
||||||
});
|
});
|
||||||
|
|
||||||
if (ticketExpiration && ticketExpiration.value == "enabled") {
|
// console.log("tickets: ", tickets);
|
||||||
const startTime = splitDateTime(
|
|
||||||
new Date(
|
|
||||||
_format(
|
|
||||||
new Date(ticketExpiration.startTime),
|
|
||||||
"yyyy-MM-dd HH:mm:ss",
|
|
||||||
{
|
|
||||||
locale: ptBR
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
const seconds = timeStringToSeconds(startTime.fullTime);
|
for (let i = 0; i < tickets.length; i++) {
|
||||||
|
|
||||||
let tickets: any = await ListTicketTimeLife({
|
await UpdateTicketService({
|
||||||
timeseconds: seconds,
|
ticketData: { status: "closed", statusChatEnd: "FINALIZADO" },
|
||||||
status: "open",
|
ticketId: tickets[i].ticket_id,
|
||||||
number: whatsapp.number
|
msg: ticketExpiration.message
|
||||||
});
|
});
|
||||||
|
|
||||||
for (let i = 0; i < tickets.length; i++) {
|
|
||||||
await UpdateTicketService({
|
|
||||||
ticketData: { status: "closed", statusChatEnd: "FINALIZADO" },
|
|
||||||
ticketId: tickets[i].ticket_id,
|
|
||||||
msg: ticketExpiration.message
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
@ -1,26 +1,37 @@
|
||||||
const fsPromises = require("fs/promises");
|
const fsPromises = require("fs/promises");
|
||||||
const fs = require("fs");
|
const fs = require('fs')
|
||||||
|
|
||||||
import ListUsersService from "../services/UserServices/ListUsersService";
|
import ListUsersService from "../services/UserServices/ListUsersService"
|
||||||
import { get } from "./RedisClient";
|
|
||||||
|
|
||||||
const _botIsOnQueue = async (botName: string) => {
|
const _botIsOnQueue = async (botName: string) => {
|
||||||
|
|
||||||
const botInfo = await get("botInfo");
|
const { users, count, hasMore } = await ListUsersService({searchParam:`${botName}`,pageNumber:1});
|
||||||
|
let botIsOnQueue = false
|
||||||
|
let userIdBot = null
|
||||||
|
let queueId = null
|
||||||
|
|
||||||
|
if(users.length > 0){
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
console.log('----------------- bot queue id: ', Object(users)[0]["queues"][0].id)
|
||||||
|
queueId = Object(users)[0]["queues"][0].id;
|
||||||
|
userIdBot = Object(users)[0].id
|
||||||
|
botIsOnQueue = true
|
||||||
|
|
||||||
|
}catch(err){
|
||||||
|
|
||||||
|
console.log('O usuário botqueue não está em nenhuma fila err: ',err)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
console.log('Usuário botqueue não existe!')
|
||||||
|
}
|
||||||
|
|
||||||
|
return { userIdBot: userIdBot, botQueueId: queueId, isOnQueue: botIsOnQueue }
|
||||||
|
|
||||||
if (
|
|
||||||
botInfo &&
|
|
||||||
botInfo?.userId &&
|
|
||||||
botInfo?.queueId &&
|
|
||||||
botInfo?.botIsOnQueue == true
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
userIdBot: botInfo.userId,
|
|
||||||
botQueueId: botInfo.queueId,
|
|
||||||
isOnQueue: botInfo.botIsOnQueue
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
return { userIdBot: null, botQueueId: null, isOnQueue: false };
|
|
||||||
};
|
|
||||||
|
|
||||||
export default _botIsOnQueue;
|
export default _botIsOnQueue;
|
|
@ -1,3 +0,0 @@
|
||||||
export function bytesToMB(bytes: number | string) {
|
|
||||||
return (+bytes / (1024 * 1024)).toFixed(2);
|
|
||||||
}
|
|
|
@ -3,22 +3,16 @@ import AppError from "../errors/AppError";
|
||||||
import Ticket from "../models/Ticket";
|
import Ticket from "../models/Ticket";
|
||||||
import ListWhatsAppsNumber from "../services/WhatsappService/ListWhatsAppsNumber";
|
import ListWhatsAppsNumber from "../services/WhatsappService/ListWhatsAppsNumber";
|
||||||
import { getSettingValue } from "./WhaticketSettings";
|
import { getSettingValue } from "./WhaticketSettings";
|
||||||
import ListWhatsAppsForQueueService from "../services/WhatsappService/ListWhatsAppsForQueueService";
|
|
||||||
|
|
||||||
const CheckContactOpenTickets = async (
|
const CheckContactOpenTickets = async (
|
||||||
contactId: number,
|
contactId: number,
|
||||||
whatsappId: number | string,
|
whatsappId: number | string
|
||||||
handle?: boolean
|
): Promise<void> => {
|
||||||
): Promise<void | any> => {
|
|
||||||
let ticket;
|
let ticket;
|
||||||
|
|
||||||
if (getSettingValue("oneContactChatWithManyWhats")?.value == "enabled") {
|
if (getSettingValue("oneContactChatWithManyWhats")?.value == "enabled") {
|
||||||
let whats = await ListWhatsAppsNumber(whatsappId);
|
let whats = await ListWhatsAppsNumber(whatsappId);
|
||||||
|
|
||||||
console.log("contactId: ", contactId, " | whatsappId: ", whatsappId);
|
|
||||||
|
|
||||||
console.log("WHATS: ", JSON.stringify(whats, null, 6));
|
|
||||||
|
|
||||||
ticket = await Ticket.findOne({
|
ticket = await Ticket.findOne({
|
||||||
where: {
|
where: {
|
||||||
[Op.and]: [
|
[Op.and]: [
|
||||||
|
@ -28,8 +22,6 @@ const CheckContactOpenTickets = async (
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("TICKET: ", JSON.stringify(ticket, null, 6));
|
|
||||||
} else {
|
} else {
|
||||||
ticket = await Ticket.findOne({
|
ticket = await Ticket.findOne({
|
||||||
where: { contactId, status: { [Op.or]: ["open", "pending"] } }
|
where: { contactId, status: { [Op.or]: ["open", "pending"] } }
|
||||||
|
@ -37,12 +29,8 @@ const CheckContactOpenTickets = async (
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ticket) {
|
if (ticket) {
|
||||||
if (handle) return true;
|
|
||||||
|
|
||||||
throw new AppError("ERR_OTHER_OPEN_TICKET");
|
throw new AppError("ERR_OTHER_OPEN_TICKET");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CheckContactOpenTickets;
|
export default CheckContactOpenTickets;
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
import { Op } from "sequelize";
|
|
||||||
import { sub, subHours } from "date-fns";
|
|
||||||
import Message from "../models/Message";
|
|
||||||
import Ticket from "../models/Ticket";
|
|
||||||
|
|
||||||
async function checkLastClientMsg24hs(ticket: Ticket) {
|
|
||||||
return await Message.findAll({
|
|
||||||
attributes: ["createdAt", "body"],
|
|
||||||
where: {
|
|
||||||
contactId: ticket.contactId,
|
|
||||||
phoneNumberId: ticket.phoneNumberId,
|
|
||||||
fromMe: false,
|
|
||||||
createdAt: {
|
|
||||||
[Op.between]: [+subHours(new Date(), 24), +new Date()]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
order: [["createdAt", "DESC"]],
|
|
||||||
limit: 1
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export default checkLastClientMsg24hs;
|
|
|
@ -1,54 +0,0 @@
|
||||||
import ListTicketTimeLife from "../services/TicketServices/ListTicketTimeLife";
|
|
||||||
import UpdateTicketService from "../services/TicketServices/UpdateTicketService";
|
|
||||||
import BotIsOnQueue from "./BotIsOnQueue";
|
|
||||||
|
|
||||||
const fsPromises = require("fs/promises");
|
|
||||||
const fs = require('fs')
|
|
||||||
|
|
||||||
let timer: any
|
|
||||||
|
|
||||||
const CloseBotTickets = async () => {
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
const botInfo = await BotIsOnQueue('botqueue')
|
|
||||||
|
|
||||||
if (!botInfo.userIdBot) return
|
|
||||||
|
|
||||||
let tickets: any = await ListTicketTimeLife({ timeseconds: 60, status: 'open', userId: botInfo.userIdBot })
|
|
||||||
|
|
||||||
console.log('tickets: ', tickets)
|
|
||||||
|
|
||||||
for (let i = 0; i < tickets.length; i++) {
|
|
||||||
|
|
||||||
await UpdateTicketService({
|
|
||||||
ticketData: { 'status': 'closed', 'userId': botInfo.userIdBot, 'statusChatEnd': 'FINALIZADO' },
|
|
||||||
ticketId: tickets[i].ticket_id
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.log('There was an error on try close the bot tickets: ', error)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const schedule = async () => {
|
|
||||||
|
|
||||||
try {
|
|
||||||
clearInterval(timer);
|
|
||||||
|
|
||||||
await CloseBotTickets()
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.log('error on schedule: ', error)
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
timer = setInterval(schedule, 60000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
timer = setInterval(schedule, 60000);
|
|
||||||
|
|
||||||
export default schedule;
|
|
|
@ -1,48 +0,0 @@
|
||||||
import ffmpeg from "fluent-ffmpeg";
|
|
||||||
|
|
||||||
import util from "util";
|
|
||||||
import { exec as execCallback } from "child_process";
|
|
||||||
|
|
||||||
const exec = util.promisify(execCallback);
|
|
||||||
|
|
||||||
async function convertAudioToOgg(
|
|
||||||
inputFile: string,
|
|
||||||
outputFile: string
|
|
||||||
): Promise<void> {
|
|
||||||
try {
|
|
||||||
const command = `ffmpeg -i ${inputFile} -c:a libopus ${outputFile}.ogg && rm ${inputFile}`;
|
|
||||||
|
|
||||||
const { stdout, stderr } = await exec(command);
|
|
||||||
|
|
||||||
console.log("Conversion finished");
|
|
||||||
console.log("stdout:", stdout);
|
|
||||||
console.error("stderr:", stderr);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error:", error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function convertAudioToWav(
|
|
||||||
inputFile: string,
|
|
||||||
outputFile: string
|
|
||||||
): Promise<void> {
|
|
||||||
return new Promise<void>((resolve, reject) => {
|
|
||||||
const command = ffmpeg(inputFile)
|
|
||||||
.audioCodec("pcm_s16le") // Set the audio codec to libvorbis (OGG)
|
|
||||||
.format("wav") // Set the output format to OGG
|
|
||||||
.on("end", () => {
|
|
||||||
console.log("Conversion finished");
|
|
||||||
resolve(); // Resolve the promise when the conversion is successful
|
|
||||||
})
|
|
||||||
.on("error", (err: any) => {
|
|
||||||
console.error("Error:", err);
|
|
||||||
reject(err); // Reject the promise if there is an error
|
|
||||||
});
|
|
||||||
|
|
||||||
// Save the output to the specified file
|
|
||||||
command.save(outputFile);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export { convertAudioToWav, convertAudioToOgg };
|
|
|
@ -1,64 +1,55 @@
|
||||||
import AppError from "../errors/AppError";
|
import AppError from "../errors/AppError";
|
||||||
import Whatsapp from "../models/Whatsapp";
|
import Whatsapp from "../models/Whatsapp";
|
||||||
|
|
||||||
import WhatsappQueue from "../models/WhatsappQueue";
|
import WhatsappQueue from "../models/WhatsappQueue"
|
||||||
import UserQueue from "../models/UserQueue";
|
import UserQueue from "../models/UserQueue"
|
||||||
|
|
||||||
import { Op, where } from "sequelize";
|
import { Op, where } from "sequelize";
|
||||||
|
|
||||||
import wbotByUserQueue from "../helpers/GetWbotByUserQueue";
|
import wbotByUserQueue from '../helpers/GetWbotByUserQueue'
|
||||||
|
|
||||||
|
// import WhatsQueueIndex from "./WhatsQueueIndex";
|
||||||
|
|
||||||
import { WhatsIndex } from "./LoadBalanceWhatsSameQueue";
|
import { WhatsIndex } from "./LoadBalanceWhatsSameQueue";
|
||||||
|
|
||||||
interface Request {
|
const GetDefaultWhatsApp = async (userId?: string | number): Promise<Whatsapp> => {
|
||||||
userId?: string | number;
|
|
||||||
queueId?: string | number;
|
|
||||||
}
|
|
||||||
|
|
||||||
//const GetDefaultWhatsApp = async (userId?: string | number): Promise<Whatsapp> => {
|
|
||||||
|
|
||||||
const GetDefaultWhatsApp = async ({
|
|
||||||
userId,
|
|
||||||
queueId
|
|
||||||
}: Request): Promise<any> => {
|
|
||||||
// test del
|
// test del
|
||||||
let defaultWhatsapp = await Whatsapp.findOne({
|
let defaultWhatsapp = await Whatsapp.findOne({
|
||||||
where: { isDefault: true }
|
where: { isDefault: true }
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!defaultWhatsapp) {
|
if (!defaultWhatsapp) {
|
||||||
|
|
||||||
|
|
||||||
if (userId) {
|
if (userId) {
|
||||||
let whatsapps = await wbotByUserQueue({ userId, queueId });
|
|
||||||
|
|
||||||
if (userId && queueId) {
|
let whatsapps = await wbotByUserQueue(userId)
|
||||||
if (whatsapps.length > 1) {
|
|
||||||
let whatsAppOfficial: any = whatsapps.find(
|
|
||||||
(w: any) => w.phoneNumberId && w.phoneNumberId.trim().length > 0
|
|
||||||
);
|
|
||||||
|
|
||||||
if (whatsAppOfficial) {
|
|
||||||
return whatsapps;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (whatsapps.length > 0) {
|
if (whatsapps.length > 0) {
|
||||||
|
|
||||||
if (whatsapps.length > 1) {
|
if (whatsapps.length > 1) {
|
||||||
defaultWhatsapp = whatsapps[+WhatsIndex(whatsapps)];
|
|
||||||
} else {
|
defaultWhatsapp = whatsapps[+WhatsIndex(whatsapps)]
|
||||||
defaultWhatsapp = whatsapps[0];
|
|
||||||
}
|
}
|
||||||
} // Quando o usuário não está em nenhuma fila
|
else {
|
||||||
|
defaultWhatsapp = whatsapps[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
}// Quando o usuário não está em nenhuma fila
|
||||||
else {
|
else {
|
||||||
defaultWhatsapp = await Whatsapp.findOne({
|
defaultWhatsapp = await Whatsapp.findOne({ where: { status: 'CONNECTED' } });
|
||||||
where: { status: "CONNECTED" }
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
defaultWhatsapp = await Whatsapp.findOne({
|
|
||||||
where: { status: "CONNECTED" }
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
defaultWhatsapp = await Whatsapp.findOne({ where: { status: 'CONNECTED' } });
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!defaultWhatsapp) {
|
if (!defaultWhatsapp) {
|
||||||
|
@ -67,6 +58,20 @@ const GetDefaultWhatsApp = async ({
|
||||||
|
|
||||||
return defaultWhatsapp;
|
return defaultWhatsapp;
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// const defaultWhatsapp = await Whatsapp.findOne({
|
||||||
|
// where: { isDefault: true }
|
||||||
|
// });
|
||||||
|
|
||||||
|
// if (!defaultWhatsapp) {
|
||||||
|
// throw new AppError("ERR_NO_DEF_WAPP_FOUND");
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return defaultWhatsapp;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default GetDefaultWhatsApp;
|
export default GetDefaultWhatsApp;
|
||||||
|
|
|
@ -7,7 +7,7 @@ const GetTicketWbot = async (ticket: Ticket): Promise<Session> => {
|
||||||
|
|
||||||
if (!ticket.whatsappId) {
|
if (!ticket.whatsappId) {
|
||||||
|
|
||||||
const defaultWhatsapp = await GetDefaultWhatsApp({});
|
const defaultWhatsapp = await GetDefaultWhatsApp();
|
||||||
|
|
||||||
await ticket.$set("whatsapp", defaultWhatsapp);
|
await ticket.$set("whatsapp", defaultWhatsapp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,64 +1,50 @@
|
||||||
|
|
||||||
import UserQueue from "../models/UserQueue";
|
import UserQueue from "../models/UserQueue";
|
||||||
import WhatsappQueue from "../models/WhatsappQueue";
|
import WhatsappQueue from "../models/WhatsappQueue";
|
||||||
import Whatsapp from "../models/Whatsapp";
|
import Whatsapp from "../models/Whatsapp";
|
||||||
|
|
||||||
import { Op, where } from "sequelize";
|
import { Op, where } from "sequelize";
|
||||||
|
|
||||||
interface Request {
|
const wbotByUserQueue = async (userId: string | number, status: string = 'CONNECTED') => {
|
||||||
userId: string | number;
|
|
||||||
status?: string;
|
let defaultWhatsapp: Whatsapp[] = []
|
||||||
queueId?: string | number;
|
|
||||||
|
try{
|
||||||
|
|
||||||
|
const queue = await UserQueue.findOne(
|
||||||
|
{
|
||||||
|
where: { userId: userId },
|
||||||
|
raw:true,
|
||||||
|
attributes: ['queueId']
|
||||||
|
});
|
||||||
|
|
||||||
|
if(queue?.queueId){
|
||||||
|
|
||||||
|
// Pega todas conexões de whatsaap que estão adicionadas à uma fila
|
||||||
|
const whatsappQueues = await WhatsappQueue.findAll(
|
||||||
|
{
|
||||||
|
where: { queueId: `${queue?.queueId }`},
|
||||||
|
raw:true,
|
||||||
|
attributes: ['whatsappId']
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
defaultWhatsapp = await Whatsapp.findAll({
|
||||||
|
where: {
|
||||||
|
id: {[Op.in]: whatsappQueues.map((w) => { return w.whatsappId })},
|
||||||
|
status: status
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}catch(err){
|
||||||
|
console.log('There was an error on select a whatsapp id by user queue: ', err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaultWhatsapp;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const wbotByUserQueue = async ({
|
|
||||||
userId,
|
|
||||||
status = "CONNECTED",
|
|
||||||
queueId
|
|
||||||
}: Request): Promise<any> => {
|
|
||||||
let defaultWhatsapp: Whatsapp[] = [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
let query: any = {};
|
|
||||||
|
|
||||||
query = { userId };
|
|
||||||
|
|
||||||
if (queueId) {
|
|
||||||
query = { ...query, queueId };
|
|
||||||
}
|
|
||||||
|
|
||||||
const queue = await UserQueue.findOne({
|
|
||||||
where: query,
|
|
||||||
raw: true,
|
|
||||||
attributes: ["queueId"]
|
|
||||||
});
|
|
||||||
|
|
||||||
if (queue?.queueId) {
|
|
||||||
// Pega todas conexões de whatsaap que estão adicionadas à uma fila
|
|
||||||
const whatsappQueues = await WhatsappQueue.findAll({
|
|
||||||
where: { queueId: `${queue?.queueId}` },
|
|
||||||
raw: true,
|
|
||||||
attributes: ["whatsappId"]
|
|
||||||
});
|
|
||||||
|
|
||||||
defaultWhatsapp = await Whatsapp.findAll({
|
|
||||||
where: {
|
|
||||||
id: {
|
|
||||||
[Op.in]: whatsappQueues.map(w => {
|
|
||||||
return w.whatsappId;
|
|
||||||
})
|
|
||||||
},
|
|
||||||
status: status
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.log(
|
|
||||||
"There was an error on select a whatsapp id by user queue: ",
|
|
||||||
err
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return defaultWhatsapp;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default wbotByUserQueue;
|
export default wbotByUserQueue;
|
||||||
|
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
import axios from "axios";
|
|
||||||
|
|
||||||
async function omnihitDashboardSession(data: any) {
|
|
||||||
|
|
||||||
// console.log('DATA: ', data)
|
|
||||||
|
|
||||||
try {
|
|
||||||
await axios.post(
|
|
||||||
`${process.env.URL_DASHBOARD_SESSIONS}/api/v1/omnihit/monitor`,
|
|
||||||
data,
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${process.env.TOKEN_DASHBOARD_SESSIONS}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
console.log(
|
|
||||||
`Post request error to ${process.env.URL_DASHBOARD_SESSIONS}/api/v1/omnihit/monitor`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default omnihitDashboardSession;
|
|
|
@ -1,73 +0,0 @@
|
||||||
import axios from "axios";
|
|
||||||
import { getIO } from "../libs/socket";
|
|
||||||
import Contact from "../models/Contact";
|
|
||||||
import Ticket from "../models/Ticket";
|
|
||||||
import {
|
|
||||||
isValidMsg,
|
|
||||||
verifyMediaMessage,
|
|
||||||
verifyMessage
|
|
||||||
} from "../services/WbotServices/wbotMessageListener";
|
|
||||||
|
|
||||||
import { writeFile } from "fs";
|
|
||||||
|
|
||||||
import whatsappOfficialAPI from "./WhatsappOfficialAPI";
|
|
||||||
import path, { join } from "path";
|
|
||||||
import { promisify } from "util";
|
|
||||||
|
|
||||||
import mime from "mime";
|
|
||||||
|
|
||||||
import fs from "fs";
|
|
||||||
import { response } from "express";
|
|
||||||
|
|
||||||
const writeFileAsync = promisify(writeFile);
|
|
||||||
|
|
||||||
async function receiveWhatsAppMediaOfficialAPI(
|
|
||||||
mediaId: string,
|
|
||||||
phoneNumberId: string
|
|
||||||
) {
|
|
||||||
try {
|
|
||||||
const { data } = await whatsappOfficialAPI.get(
|
|
||||||
`/${process.env.VERSION}/${mediaId}?phone_number_id=${phoneNumberId}`
|
|
||||||
);
|
|
||||||
|
|
||||||
if (data && data?.url) {
|
|
||||||
const config: any = {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${process.env.TOKEN}`
|
|
||||||
},
|
|
||||||
responseType: "arraybuffer"
|
|
||||||
};
|
|
||||||
|
|
||||||
const filename = Date.now() + String(Math.floor(Math.random() * 1000));
|
|
||||||
|
|
||||||
const response = await axios.get(data.url, config);
|
|
||||||
|
|
||||||
const ext = response.headers["content-type"].split("/")[1];
|
|
||||||
|
|
||||||
const filename_ext = `${filename}.${ext}`;
|
|
||||||
|
|
||||||
const destPath = path.join(
|
|
||||||
__dirname,
|
|
||||||
`..`,
|
|
||||||
`..`,
|
|
||||||
`..`,
|
|
||||||
`..`,
|
|
||||||
`public`,
|
|
||||||
`${filename_ext}`
|
|
||||||
);
|
|
||||||
|
|
||||||
fs.writeFileSync(destPath, response.data);
|
|
||||||
|
|
||||||
return filename_ext;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log(
|
|
||||||
"There was an error on receiveWhatsAppMediaOfficialAPI: ",
|
|
||||||
error
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default receiveWhatsAppMediaOfficialAPI;
|
|
|
@ -1,130 +0,0 @@
|
||||||
const Redis = require("ioredis");
|
|
||||||
const redis = new Redis(process.env.REDIS_URI);
|
|
||||||
|
|
||||||
type WhatsappData = {
|
|
||||||
whatsappId: string;
|
|
||||||
contactId: string;
|
|
||||||
identifier: string;
|
|
||||||
value?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export async function set(key: string, value: string) {
|
|
||||||
await redis.set(key, JSON.stringify(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function get(key: string) {
|
|
||||||
const value: any = await redis.get(key);
|
|
||||||
return JSON.parse(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function createObject({
|
|
||||||
whatsappId,
|
|
||||||
contactId,
|
|
||||||
identifier,
|
|
||||||
value
|
|
||||||
}: WhatsappData) {
|
|
||||||
const key = `whatsappId:${whatsappId}:contactId:${contactId}:identifier:${identifier}`;
|
|
||||||
const result = await redis.hmset(
|
|
||||||
key,
|
|
||||||
"whatsappId",
|
|
||||||
whatsappId,
|
|
||||||
"contactId",
|
|
||||||
contactId,
|
|
||||||
"identifier",
|
|
||||||
identifier,
|
|
||||||
"value",
|
|
||||||
value
|
|
||||||
);
|
|
||||||
|
|
||||||
await redis.expire(key, 300);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function updateObject({
|
|
||||||
whatsappId,
|
|
||||||
contactId,
|
|
||||||
identifier,
|
|
||||||
value
|
|
||||||
}: WhatsappData) {
|
|
||||||
const key = `whatsappId:${whatsappId}:contactId:${contactId}:identifier:${identifier}`;
|
|
||||||
|
|
||||||
await redis.hset(key, "value", value);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function findObject(
|
|
||||||
whatsappId: string,
|
|
||||||
contactId: string,
|
|
||||||
identifier: string
|
|
||||||
) {
|
|
||||||
const key = `whatsappId:${whatsappId}:contactId:${contactId}:identifier:${identifier}`;
|
|
||||||
const result = await redis.hmget(
|
|
||||||
key,
|
|
||||||
"whatsappId",
|
|
||||||
"contactId",
|
|
||||||
"identifier",
|
|
||||||
"value"
|
|
||||||
);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function deleteObject(
|
|
||||||
whatsappId: string,
|
|
||||||
contactId: string,
|
|
||||||
identifier: string
|
|
||||||
) {
|
|
||||||
const key = `whatsappId:${whatsappId}:contactId:${contactId}:identifier:${identifier}`;
|
|
||||||
const deletedCount = await redis.del(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function deleteKeysWithPattern(
|
|
||||||
whatsappId: string,
|
|
||||||
contactId: string
|
|
||||||
) {
|
|
||||||
const pattern = `whatsappId:${whatsappId}:contactId:${contactId}:*`;
|
|
||||||
|
|
||||||
let cursor = "0";
|
|
||||||
|
|
||||||
do {
|
|
||||||
const [newCursor, keys] = await redis.scan(
|
|
||||||
cursor,
|
|
||||||
"MATCH",
|
|
||||||
pattern,
|
|
||||||
"COUNT",
|
|
||||||
"100"
|
|
||||||
);
|
|
||||||
|
|
||||||
for (const key of keys) {
|
|
||||||
await redis.del(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
cursor = newCursor;
|
|
||||||
} while (cursor !== "0");
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getHashesWithPattern(
|
|
||||||
whatsappId: string,
|
|
||||||
contactId: string
|
|
||||||
) {
|
|
||||||
const pattern = `whatsappId:${whatsappId}:contactId:${contactId}:*`;
|
|
||||||
|
|
||||||
let cursor = "0";
|
|
||||||
const hashes = [];
|
|
||||||
|
|
||||||
do {
|
|
||||||
const [newCursor, keys] = await redis.scan(
|
|
||||||
cursor,
|
|
||||||
"MATCH",
|
|
||||||
pattern,
|
|
||||||
"COUNT",
|
|
||||||
"100"
|
|
||||||
);
|
|
||||||
|
|
||||||
for (const key of keys) {
|
|
||||||
const hash = await redis.hgetall(key);
|
|
||||||
hashes.push(hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
cursor = newCursor;
|
|
||||||
} while (cursor !== "0");
|
|
||||||
|
|
||||||
return hashes;
|
|
||||||
}
|
|
|
@ -11,140 +11,179 @@ import { convertBytes } from "./ConvertBytes";
|
||||||
import { deleteScheduleByTicketIdCache } from "./SchedulingNotifyCache";
|
import { deleteScheduleByTicketIdCache } from "./SchedulingNotifyCache";
|
||||||
import SchedulingNotify from "../models/SchedulingNotify";
|
import SchedulingNotify from "../models/SchedulingNotify";
|
||||||
import Ticket from "../models/Ticket";
|
import Ticket from "../models/Ticket";
|
||||||
import User from "../models/User";
|
|
||||||
import { Sequelize, Op } from "sequelize";
|
import { Sequelize, Op } from "sequelize";
|
||||||
import omnihitDashboardSession from "./OmnhitDashboardSession";
|
|
||||||
|
|
||||||
const fastFolderSize = require("fast-folder-size");
|
|
||||||
const { promisify } = require("util");
|
const fastFolderSize = require('fast-folder-size')
|
||||||
const fs = require("fs");
|
const { promisify } = require('util')
|
||||||
|
const fs = require('fs')
|
||||||
|
|
||||||
const { exec } = require("child_process");
|
const { exec } = require("child_process");
|
||||||
|
|
||||||
let _fifo: any;
|
let _fifo: any
|
||||||
|
|
||||||
let scheduler_monitor: any;
|
let scheduler_monitor: any;
|
||||||
let timeInterval = 5;
|
let timeInterval = 5
|
||||||
|
|
||||||
const monitor = async () => {
|
const monitor = async () => {
|
||||||
let date = new Date();
|
|
||||||
|
|
||||||
let day = date.getDate().toString().padStart(2, "0");
|
let date = new Date()
|
||||||
let month = (date.getMonth() + 1).toString().padStart(2, "0");
|
|
||||||
let year = date.getFullYear();
|
|
||||||
|
|
||||||
let hour = date.getHours();
|
let day = date.getDate().toString().padStart(2, '0');
|
||||||
let minute = date.getMinutes();
|
let month = (date.getMonth() + 1).toString().padStart(2, '0');
|
||||||
|
let year = date.getFullYear();
|
||||||
|
|
||||||
let fullDate = `${year}-${month}-${day}`;
|
let hour = date.getHours()
|
||||||
let dateParm = `${fullDate} ${hour.toString().padStart(2, "0")}:${minute
|
let minute = date.getMinutes()
|
||||||
.toString()
|
|
||||||
.padStart(2, "0")}:00`;
|
|
||||||
|
|
||||||
//console.log(dateParm);
|
let fullDate = `${year}-${month}-${day}`;
|
||||||
|
let dateParm = `${fullDate} ${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}:00`
|
||||||
|
|
||||||
try {
|
//console.log(dateParm);
|
||||||
const { schedulingNotifies, count, hasMore } =
|
|
||||||
await ListSchedulingNotifyService({
|
|
||||||
searchParam: dateParm,
|
|
||||||
pageNumber: "1"
|
|
||||||
});
|
|
||||||
|
|
||||||
if (schedulingNotifies && schedulingNotifies.length > 0) {
|
try {
|
||||||
for (let i = 0; i < schedulingNotifies.length; i++) {
|
|
||||||
const ticket: any = await ShowTicketService(
|
|
||||||
+schedulingNotifies[i].ticketId
|
|
||||||
);
|
|
||||||
|
|
||||||
let _ticket = await Ticket.findOne({
|
const { schedulingNotifies, count, hasMore } = await ListSchedulingNotifyService({ searchParam: dateParm, pageNumber: "1" });
|
||||||
where: {
|
|
||||||
contactId: ticket.contactId,
|
|
||||||
status: { [Op.in]: ["open", "pending"] }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await deleteScheduleByTicketIdCache(schedulingNotifies[i].ticketId);
|
if (schedulingNotifies && schedulingNotifies.length > 0) {
|
||||||
|
|
||||||
await DeleteSchedulingNotifyService(schedulingNotifies[i].id);
|
for (let i = 0; i < schedulingNotifies.length; i++) {
|
||||||
|
|
||||||
if (_ticket) continue;
|
const ticket: any = await ShowTicketService(+schedulingNotifies[i].ticketId);
|
||||||
|
|
||||||
|
let _ticket = await Ticket.findOne({
|
||||||
|
where: {
|
||||||
|
contactId: ticket.contactId,
|
||||||
|
status: { [Op.in]: ['open', 'pending'] }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
await deleteScheduleByTicketIdCache(schedulingNotifies[i].ticketId)
|
||||||
|
|
||||||
|
await DeleteSchedulingNotifyService(schedulingNotifies[i].id)
|
||||||
|
|
||||||
|
if (_ticket) continue
|
||||||
|
|
||||||
|
if (ticket.dataValues.status == 'closed') {
|
||||||
|
await ticket.update({ status: 'pending' })
|
||||||
|
}
|
||||||
|
|
||||||
|
await new Promise(f => setTimeout(f, 3000));
|
||||||
|
await SendWhatsAppMessage({
|
||||||
|
body: schedulingNotifies[i].message, ticket
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (ticket.dataValues.status == "closed") {
|
|
||||||
await ticket.update({ status: "open" });
|
|
||||||
}
|
|
||||||
const userId: number = ticket.getDataValue("userId");
|
|
||||||
let userN = "";
|
|
||||||
if (userId) {
|
|
||||||
const useer = await User.findByPk(userId);
|
|
||||||
if (useer) {
|
|
||||||
const userName: string = useer.getDataValue("name");
|
|
||||||
userN = `*${userName}:* \n`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await new Promise(f => setTimeout(f, 3000));
|
|
||||||
await SendWhatsAppMessage({
|
exec("df -h /", (error: any, stdout: any, stderr: any) => {
|
||||||
body: userN + schedulingNotifies[i].message,
|
|
||||||
ticket
|
if (error) {
|
||||||
|
console.log(`exec error: ${error.message}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (stderr) {
|
||||||
|
console.log(`exec stderr: ${stderr}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
stdout = stdout.split(/\r?\n/)
|
||||||
|
stdout = stdout[1].trim().split(/\s+/)
|
||||||
|
|
||||||
|
// DISK SPACE MONITORING
|
||||||
|
const io = getIO();
|
||||||
|
io.emit("diskSpaceMonit", {
|
||||||
|
action: "update",
|
||||||
|
diskSpace: {
|
||||||
|
size: stdout[1],
|
||||||
|
used: stdout[2],
|
||||||
|
available: stdout[3],
|
||||||
|
use: stdout[4]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
// WHATS SESSION SIZE MONITORING
|
||||||
|
// const whatsapps = await ListWhatsAppsService();
|
||||||
|
|
||||||
|
// whatsapps.forEach(async whats => {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// const sourcePath = path.join(__dirname, `../../.wwebjs_auth/`, `session-bd_${whats.id}`)
|
||||||
|
|
||||||
|
// if (fs.existsSync(sourcePath)) {
|
||||||
|
|
||||||
|
// try {
|
||||||
|
|
||||||
|
// const fastFolderSizeAsync = promisify(fastFolderSize)
|
||||||
|
|
||||||
|
// let size = await fastFolderSizeAsync(sourcePath)
|
||||||
|
|
||||||
|
// size = convertBytes(size)
|
||||||
|
|
||||||
|
|
||||||
|
// // SESSION MONITORING
|
||||||
|
// const io = getIO();
|
||||||
|
// io.emit("whatsappSessionMonit", {
|
||||||
|
// action: "update",
|
||||||
|
// whatsappSessionSize: {
|
||||||
|
// id: whats.id,
|
||||||
|
// sessionSize: size
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// catch (err) {
|
||||||
|
// console.log('An error occurred while get info from the directory: ', err);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
|
||||||
|
// // console.log('Directory not found to get size info: ', sourcePath)
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// });
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.log('>>> SchedulingNotifiySendMessage.ts error: ', error)
|
||||||
}
|
}
|
||||||
|
|
||||||
exec("df -h /", (error: any, stdout: any, stderr: any) => {
|
|
||||||
if (error) {
|
|
||||||
console.log(`exec error: ${error.message}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (stderr) {
|
|
||||||
console.log(`exec stderr: ${stderr}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
stdout = stdout.split(/\r?\n/);
|
|
||||||
stdout = stdout[1].trim().split(/\s+/);
|
|
||||||
|
|
||||||
// DISK SPACE MONITORING
|
|
||||||
const io = getIO();
|
|
||||||
io.emit("diskSpaceMonit", {
|
|
||||||
action: "update",
|
|
||||||
diskSpace: {
|
|
||||||
size: stdout[1],
|
|
||||||
used: stdout[2],
|
|
||||||
available: stdout[3],
|
|
||||||
use: stdout[4]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let data: any = {};
|
|
||||||
|
|
||||||
data.diskSpace = {
|
|
||||||
DB: process.env.DB_NAME,
|
|
||||||
size: stdout[1],
|
|
||||||
used: stdout[2],
|
|
||||||
available: stdout[3],
|
|
||||||
use: stdout[4]
|
|
||||||
};
|
|
||||||
data.action = "update";
|
|
||||||
omnihitDashboardSession(data);
|
|
||||||
});
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.log(">>> SchedulingNotifiySendMessage.ts error: ", error);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const SchedulingNotifySendMessage = async () => {
|
const SchedulingNotifySendMessage = async () => {
|
||||||
try {
|
|
||||||
clearInterval(_fifo);
|
|
||||||
|
|
||||||
await monitor();
|
try {
|
||||||
} catch (error) {
|
clearInterval(_fifo);
|
||||||
console.log("error on SchedulingNotifySendMessage: ", error);
|
|
||||||
} finally {
|
await monitor()
|
||||||
_fifo = setInterval(SchedulingNotifySendMessage, 5000);
|
|
||||||
}
|
} catch (error) {
|
||||||
};
|
console.log('error on SchedulingNotifySendMessage: ', error)
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
_fifo = setInterval(SchedulingNotifySendMessage, 5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_fifo = setInterval(SchedulingNotifySendMessage, 5000);
|
_fifo = setInterval(SchedulingNotifySendMessage, 5000);
|
||||||
|
|
||||||
module.exports = SchedulingNotifySendMessage;
|
|
||||||
|
module.exports = SchedulingNotifySendMessage
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,33 +1,21 @@
|
||||||
import { getIO } from "../libs/socket";
|
import { getIO } from "../libs/socket";
|
||||||
import Ticket from "../models/Ticket";
|
import Ticket from "../models/Ticket";
|
||||||
import sendWhatsAppMessageOfficialAPI from "./sendWhatsAppMessageOfficialAPI"
|
|
||||||
|
|
||||||
function sendWhatsAppMessageSocket(
|
|
||||||
ticket: Ticket,
|
|
||||||
body: string,
|
|
||||||
quotedMsgSerializedId?: string | undefined,
|
|
||||||
number?: string
|
|
||||||
) {
|
|
||||||
const { phoneNumberId } = ticket;
|
|
||||||
|
|
||||||
if (phoneNumberId) {
|
function sendWhatsAppMessageSocket(ticket: Ticket, body: string, quotedMsgSerializedId?: string | undefined, number?: string ) {
|
||||||
sendWhatsAppMessageOfficialAPI(ticket, body, quotedMsgSerializedId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const io = getIO();
|
const io = getIO();
|
||||||
|
|
||||||
|
io.to(`session_${ticket.whatsappId.toString()}`).emit("send_message", {
|
||||||
|
action: "create",
|
||||||
|
msg: {
|
||||||
|
number: number ? number : `${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us`,
|
||||||
|
body: body,
|
||||||
|
quotedMessageId: quotedMsgSerializedId,
|
||||||
|
linkPreview: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
io.to(`session_${ticket.whatsappId.toString()}`).emit("send_message", {
|
|
||||||
action: "create",
|
|
||||||
msg: {
|
|
||||||
number: number
|
|
||||||
? number
|
|
||||||
: `${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us`,
|
|
||||||
body: body,
|
|
||||||
quotedMessageId: quotedMsgSerializedId,
|
|
||||||
linkPreview: false
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default sendWhatsAppMessageSocket;
|
export default sendWhatsAppMessageSocket;
|
|
@ -4,7 +4,6 @@ import User from "../models/User";
|
||||||
interface SerializedUser {
|
interface SerializedUser {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
positionCompany: string;
|
|
||||||
email: string;
|
email: string;
|
||||||
profile: string;
|
profile: string;
|
||||||
queues: Queue[];
|
queues: Queue[];
|
||||||
|
@ -14,7 +13,6 @@ export const SerializeUser = (user: User): SerializedUser => {
|
||||||
return {
|
return {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
name: user.name,
|
name: user.name,
|
||||||
positionCompany: user.positionCompany,
|
|
||||||
email: user.email,
|
email: user.email,
|
||||||
profile: user.profile,
|
profile: user.profile,
|
||||||
queues: user.queues
|
queues: user.queues
|
||||||
|
|
|
@ -1,27 +1,12 @@
|
||||||
import { Op } from "sequelize"
|
|
||||||
import { getWbot } from "../libs/wbot";
|
import { getWbot } from "../libs/wbot";
|
||||||
import Message from "../models/Message"
|
|
||||||
import Ticket from "../models/Ticket";
|
import Ticket from "../models/Ticket";
|
||||||
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) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const wbot_url = await getWbot(ticket.whatsappId);
|
const wbot_url = await getWbot(ticket.whatsappId);
|
||||||
|
|
||||||
console.log(
|
console.log('from wbotMessagelistener wbot_url: ', wbot_url, ' | ticket.contact.number: ', ticket.contact.number);
|
||||||
"from wbotMessagelistener wbot_url: ",
|
|
||||||
wbot_url,
|
|
||||||
" | ticket.contact.number: ",
|
|
||||||
ticket.contact.number
|
|
||||||
);
|
|
||||||
|
|
||||||
await endPointQuery(`${wbot_url}/api/sendSeen`, {
|
await endPointQuery(`${wbot_url}/api/sendSeen`, { number: `${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us` });
|
||||||
number: `${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us`
|
|
||||||
});
|
|
||||||
}
|
}
|
|
@ -13,11 +13,11 @@ import {
|
||||||
} from "date-fns";
|
} from "date-fns";
|
||||||
import ptBR from "date-fns/locale/pt-BR";
|
import ptBR from "date-fns/locale/pt-BR";
|
||||||
|
|
||||||
const isHoliday = async (number: string | number) => {
|
const isHoliday = async () => {
|
||||||
let obj = { set: false, msg: "" };
|
let obj = { set: false, msg: "" };
|
||||||
|
|
||||||
const holiday = await SettingTicket.findOne({
|
const holiday = await SettingTicket.findOne({
|
||||||
where: { key: "holiday", number }
|
where: { key: "holiday" }
|
||||||
});
|
});
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
@ -50,11 +50,11 @@ const isHoliday = async (number: string | number) => {
|
||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
|
|
||||||
const isWeekend = async (number: string | number) => {
|
const isWeekend = async () => {
|
||||||
let obj = { set: false, msg: "" };
|
let obj = { set: false, msg: "" };
|
||||||
|
|
||||||
const weekend = await SettingTicket.findOne({
|
const weekend = await SettingTicket.findOne({
|
||||||
where: { key: "weekend", number }
|
where: { key: "weekend" }
|
||||||
});
|
});
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
@ -62,6 +62,7 @@ const isWeekend = async (number: string | number) => {
|
||||||
weekend.value == "enabled" &&
|
weekend.value == "enabled" &&
|
||||||
weekend.message?.trim()?.length > 0
|
weekend.message?.trim()?.length > 0
|
||||||
) {
|
) {
|
||||||
|
|
||||||
// Specify your desired timezone
|
// Specify your desired timezone
|
||||||
const brazilTimeZone = "America/Sao_Paulo";
|
const brazilTimeZone = "America/Sao_Paulo";
|
||||||
|
|
||||||
|
@ -99,7 +100,8 @@ const isWeekend = async (number: string | number) => {
|
||||||
obj.set = true;
|
obj.set = true;
|
||||||
obj.msg = weekend.message;
|
obj.msg = weekend.message;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else{
|
||||||
// obj.set = true;
|
// obj.set = true;
|
||||||
// obj.msg = weekend.message;
|
// obj.msg = weekend.message;
|
||||||
}
|
}
|
||||||
|
@ -107,11 +109,11 @@ const isWeekend = async (number: string | number) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
async function isOutBusinessTime(number: string | number) {
|
async function isOutBusinessTime() {
|
||||||
let obj = { set: false, msg: "" };
|
let obj = { set: false, msg: "" };
|
||||||
|
|
||||||
const outBusinessHours = await SettingTicket.findOne({
|
const outBusinessHours = await SettingTicket.findOne({
|
||||||
where: { key: "outBusinessHours", number }
|
where: { key: "outBusinessHours" }
|
||||||
});
|
});
|
||||||
|
|
||||||
let isWithinRange = false;
|
let isWithinRange = false;
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
|
||||||
|
import Ticket from "../models/Ticket";
|
||||||
|
import ListWhatsAppsNumber from "../services/WhatsappService/ListWhatsAppsNumber";
|
||||||
|
import GetTicketWbot from "./GetTicketWbot";
|
||||||
|
|
||||||
|
const sendMessageMultiSession = async (ticket: Ticket, body?: any, quotedMsgSerializedId?: any, sendSeen?: boolean) => {
|
||||||
|
|
||||||
|
let sentMessage: any = ''
|
||||||
|
|
||||||
|
const listWhatsapp: any = await ListWhatsAppsNumber(ticket.whatsappId, 'CONNECTED')
|
||||||
|
|
||||||
|
if (listWhatsapp.length > 0) {
|
||||||
|
|
||||||
|
for (let w = 0; w < listWhatsapp.length; w++) {
|
||||||
|
|
||||||
|
if(listWhatsapp[w].id == ticket.whatsappId) continue
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
console.log('CHANGE THE WHATSAPP SESSION ID: ', listWhatsapp[w].id)
|
||||||
|
|
||||||
|
await ticket.update({ whatsappId: listWhatsapp[w].id })
|
||||||
|
|
||||||
|
const wbot = await GetTicketWbot(ticket);
|
||||||
|
|
||||||
|
if (sendSeen) {
|
||||||
|
|
||||||
|
await wbot.sendSeen(`${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us`);
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (body) {
|
||||||
|
|
||||||
|
sentMessage = await wbot.sendMessage(`${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us`, body, { quotedMessageId: quotedMsgSerializedId, linkPreview: false });
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.log('Cannot send send the message using the whatsapp id: ', listWhatsapp[w].id, ' | error: ', error)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sentMessage
|
||||||
|
};
|
||||||
|
|
||||||
|
export default sendMessageMultiSession;
|
|
@ -1,11 +0,0 @@
|
||||||
import axios from "axios";
|
|
||||||
|
|
||||||
const api = axios.create({
|
|
||||||
baseURL: process.env.URL_WHATSAPP_API,
|
|
||||||
headers: {
|
|
||||||
Accept: "application/json",
|
|
||||||
Authorization: `Bearer ${process.env.TOKEN}`
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default api;
|
|
|
@ -1,21 +0,0 @@
|
||||||
import whatsappOfficialAPI from "./WhatsappOfficialAPI";
|
|
||||||
|
|
||||||
async function whatsappOfficialNumberInfo(wabaId: string) {
|
|
||||||
try {
|
|
||||||
const { data } = await whatsappOfficialAPI.get(
|
|
||||||
`/${process.env.VERSION}/${wabaId}/phone_numbers`
|
|
||||||
);
|
|
||||||
console.log("data: ", data);
|
|
||||||
|
|
||||||
if (data && Object.keys(data).length > 0) {
|
|
||||||
return data.data[0];
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log(
|
|
||||||
`There was an error into whatsappOfficialNumberInfo method : ${error}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
export default whatsappOfficialNumberInfo;
|
|
|
@ -67,7 +67,7 @@ const monitor = async () => {
|
||||||
|
|
||||||
const usersSocket = require('./../libs/socket');
|
const usersSocket = require('./../libs/socket');
|
||||||
|
|
||||||
if (usersSocket?.ob) {
|
if (usersSocket.ob) {
|
||||||
|
|
||||||
if (count > 1) {
|
if (count > 1) {
|
||||||
count = 0
|
count = 0
|
||||||
|
|
|
@ -1,28 +1,39 @@
|
||||||
const fsPromises = require("fs/promises");
|
const fsPromises = require("fs/promises");
|
||||||
const fs = require("fs");
|
const fs = require('fs')
|
||||||
import axios from "axios";
|
import axios from 'axios';
|
||||||
import * as https from "https";
|
import * as https from "https";
|
||||||
|
|
||||||
const endPointQuery = async (url: string, data: any) => {
|
const endPointQuery = async (url: string, data: any) => {
|
||||||
let response: any = null;
|
|
||||||
|
|
||||||
try {
|
let response: any = null
|
||||||
response = await axios.post(url, data);
|
|
||||||
|
|
||||||
console.log(
|
try {
|
||||||
`TEST URL CLIENT POST ROUTE: ${url} | STATUS CODE: ${response.status}`
|
|
||||||
);
|
response = await axios.post(url, data);
|
||||||
} catch (err: any) {
|
|
||||||
if (err.response) {
|
console.log(`TEST URL CLIENT POST ROUTE: ${url} | STATUS CODE: ${response.status}`);
|
||||||
console.log("err.response: ", err.response);
|
|
||||||
} else if (err.request) {
|
|
||||||
console.log("err.request: ", err.request);
|
} catch (err: any) {
|
||||||
} else {
|
|
||||||
console.error(`Erro ao consultar endpoint ${url}: ${err}`);
|
if (err.response) {
|
||||||
|
// The client was given an error response (5xx, 4xx)
|
||||||
|
// console.log('err.response: ', err.response)
|
||||||
|
console.log('err.response: ', err.response)
|
||||||
|
|
||||||
|
// return { data: err.response.data, status: err.response.status }
|
||||||
|
|
||||||
|
} else if (err.request) {
|
||||||
|
// The client never received a response, and the request was never left
|
||||||
|
console.log('err.request: ', err.request)
|
||||||
|
} else {
|
||||||
|
// Anything else
|
||||||
|
console.error(`Erro ao consultar endpoint ${url}: ${err}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return response;
|
return response
|
||||||
};
|
|
||||||
|
}
|
||||||
|
|
||||||
export default endPointQuery;
|
export default endPointQuery;
|
|
@ -1,17 +0,0 @@
|
||||||
const usersSocket = require("../libs/socket");
|
|
||||||
|
|
||||||
export const removeUserFromOlineList = (userId: any) => {
|
|
||||||
let index = usersSocket?.ob?.listOnline?.findIndex((o: any) => o?.id == userId);
|
|
||||||
|
|
||||||
if (index != -1) {
|
|
||||||
usersSocket?.ob?.listOnline?.splice(index, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
index = -1;
|
|
||||||
|
|
||||||
index = usersSocket?.ob?.listOnlineAux?.findIndex((o: any) => o?.id == userId);
|
|
||||||
|
|
||||||
if (index != -1) {
|
|
||||||
usersSocket?.ob?.listOnlineAux?.splice(index, 1);
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,81 +0,0 @@
|
||||||
import { getIO } from "../libs/socket";
|
|
||||||
import Contact from "../models/Contact";
|
|
||||||
import Ticket from "../models/Ticket";
|
|
||||||
import {
|
|
||||||
isValidMsg,
|
|
||||||
verifyMessage
|
|
||||||
} from "../services/WbotServices/wbotMessageListener";
|
|
||||||
|
|
||||||
import whatsappOfficialAPI from "./WhatsappOfficialAPI";
|
|
||||||
|
|
||||||
async function sendWhatsAppMessageOfficialAPI(
|
|
||||||
ticket: Ticket,
|
|
||||||
body: string,
|
|
||||||
quotedMsgSerializedId?: any | undefined,
|
|
||||||
_template?: any
|
|
||||||
) {
|
|
||||||
const { contactId, phoneNumberId } = ticket;
|
|
||||||
|
|
||||||
const contact: any = await Contact.findByPk(contactId);
|
|
||||||
|
|
||||||
const { number } = contact;
|
|
||||||
|
|
||||||
let data: any = {
|
|
||||||
messaging_product: "whatsapp",
|
|
||||||
recipient_type: "individual",
|
|
||||||
to: number
|
|
||||||
};
|
|
||||||
|
|
||||||
if (_template) {
|
|
||||||
const { template } = _template;
|
|
||||||
data = {
|
|
||||||
...data,
|
|
||||||
type: "template",
|
|
||||||
template
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
data = {
|
|
||||||
...data,
|
|
||||||
type: "text",
|
|
||||||
text: {
|
|
||||||
preview_url: true,
|
|
||||||
body
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (quotedMsgSerializedId) {
|
|
||||||
data = { ...data, context: { message_id: quotedMsgSerializedId.id } };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isValidMsg({ type: data.type })) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("SEND MESSAGE: ", JSON.stringify(data, null,2));
|
|
||||||
|
|
||||||
whatsappOfficialAPI
|
|
||||||
.post(`/${process.env.VERSION}/${phoneNumberId}/messages`, data)
|
|
||||||
.then(response => {
|
|
||||||
console.log("Response:", response.data);
|
|
||||||
|
|
||||||
let msg = {};
|
|
||||||
|
|
||||||
msg = {
|
|
||||||
...msg,
|
|
||||||
id: { id: response.data.messages[0].id },
|
|
||||||
fromMe: true,
|
|
||||||
type: "chat",
|
|
||||||
read: false,
|
|
||||||
phoneNumberId,
|
|
||||||
body
|
|
||||||
};
|
|
||||||
|
|
||||||
verifyMessage(msg, ticket, contact, quotedMsgSerializedId?.id);
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.log("Error on try request: ", error.response.data.error.message);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export default sendWhatsAppMessageOfficialAPI;
|
|
|
@ -1,106 +0,0 @@
|
||||||
import { MessageMedia } from "whatsapp-web.js";
|
|
||||||
import { getIO } from "../libs/socket";
|
|
||||||
import Contact from "../models/Contact";
|
|
||||||
import Ticket from "../models/Ticket";
|
|
||||||
import {
|
|
||||||
isValidMsg,
|
|
||||||
mediaTypeWhatsappOfficial,
|
|
||||||
verifyMediaMessage,
|
|
||||||
verifyMessage
|
|
||||||
} from "../services/WbotServices/wbotMessageListener";
|
|
||||||
|
|
||||||
import ffmpeg from "fluent-ffmpeg";
|
|
||||||
import fs from "fs";
|
|
||||||
|
|
||||||
import whatsappOfficialAPI from "./WhatsappOfficialAPI";
|
|
||||||
import path from "path";
|
|
||||||
|
|
||||||
import { convertAudioToOgg } from "../helpers/ConvertAudio";
|
|
||||||
import { bytesToMB } from "./BytesToMB";
|
|
||||||
import isThisHour from "date-fns/esm/isThisHour/index";
|
|
||||||
import AppError from "../errors/AppError";
|
|
||||||
|
|
||||||
async function sendWhatsMediaOfficialAPI(
|
|
||||||
ticket: Ticket,
|
|
||||||
media: any,
|
|
||||||
type: any,
|
|
||||||
mic_audio?: any
|
|
||||||
) {
|
|
||||||
const { contactId, phoneNumberId } = ticket;
|
|
||||||
|
|
||||||
const contact: any = await Contact.findByPk(contactId);
|
|
||||||
|
|
||||||
const { number } = contact;
|
|
||||||
|
|
||||||
let { filename } = MessageMedia.fromFilePath(media.path);
|
|
||||||
|
|
||||||
const { originalname } = media;
|
|
||||||
|
|
||||||
console.log("mic_audio: ", mic_audio);
|
|
||||||
|
|
||||||
if (type == "audio" && mic_audio) {
|
|
||||||
const inputFile = media.path;
|
|
||||||
|
|
||||||
const fileNameWithoutExtension = path.basename(
|
|
||||||
media.path,
|
|
||||||
path.extname(media.path)
|
|
||||||
);
|
|
||||||
|
|
||||||
const outputFile = `${
|
|
||||||
inputFile.split(fileNameWithoutExtension)[0]
|
|
||||||
}${fileNameWithoutExtension}`;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await convertAudioToOgg(inputFile, outputFile);
|
|
||||||
media = MessageMedia.fromFilePath(`${outputFile}.ogg`);
|
|
||||||
filename = media.filename;
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Conversion failed:", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let data: any = {
|
|
||||||
messaging_product: "whatsapp",
|
|
||||||
recipient_type: "individual",
|
|
||||||
to: number,
|
|
||||||
type,
|
|
||||||
[type]: {
|
|
||||||
link: `${process.env.URL_WHATSAPP_MEDIA}/${filename}`
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (type == "document") {
|
|
||||||
data.document = { ...data.document, filename: originalname };
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("PAYLOAD MEDIA: ", data);
|
|
||||||
|
|
||||||
if (!isValidMsg({ type })) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
whatsappOfficialAPI
|
|
||||||
.post(`/${process.env.VERSION}/${phoneNumberId}/messages`, data)
|
|
||||||
.then(response => {
|
|
||||||
console.log("Response:", response.data);
|
|
||||||
|
|
||||||
let msg = {};
|
|
||||||
|
|
||||||
msg = {
|
|
||||||
...msg,
|
|
||||||
id: { id: response.data.messages[0].id },
|
|
||||||
ticketId: ticket.id,
|
|
||||||
body: filename,
|
|
||||||
fromMe: true,
|
|
||||||
read: false,
|
|
||||||
phoneNumberId
|
|
||||||
};
|
|
||||||
|
|
||||||
verifyMediaMessage(msg, ticket, contact, media);
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.log("Error on try request: ", error.response.data.error.message);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export default sendWhatsMediaOfficialAPI;
|
|
|
@ -139,7 +139,7 @@ export const initIO = (httpServer: Server): SocketIO => {
|
||||||
lstOnline.push({ id: userId, status: "online", try: 0 });
|
lstOnline.push({ id: userId, status: "online", try: 0 });
|
||||||
|
|
||||||
lstOnlineAux.push({ id: userId });
|
lstOnlineAux.push({ id: userId });
|
||||||
console.log(" 1 - PUSHED NEW USER ID 1: ", userId);
|
console.log(" 1 PUSHED NEW USER ID 1: ", userId);
|
||||||
|
|
||||||
obj.listOnline = lstOnline;
|
obj.listOnline = lstOnline;
|
||||||
} else {
|
} else {
|
||||||
|
@ -154,7 +154,7 @@ export const initIO = (httpServer: Server): SocketIO => {
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
lstOnline.push({ id: userId, status: "online", try: 0 });
|
lstOnline.push({ id: userId, status: "online", try: 0 });
|
||||||
|
|
||||||
console.log(" 2 - PUSHED NEW USER ID: ", userId);
|
console.log(" 2 PUSHED NEW USER ID: ", userId);
|
||||||
|
|
||||||
obj.listOnline = lstOnline;
|
obj.listOnline = lstOnline;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -23,7 +23,6 @@ const isAuth = (req: Request, res: Response, next: NextFunction): void => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const decoded = verify(token, authConfig.secret);
|
const decoded = verify(token, authConfig.secret);
|
||||||
|
|
||||||
const { id, profile } = decoded as TokenPayload;
|
const { id, profile } = decoded as TokenPayload;
|
||||||
|
|
||||||
req.user = {
|
req.user = {
|
||||||
|
|
|
@ -34,15 +34,10 @@ class Message extends Model<Message> {
|
||||||
@Column(DataType.TEXT)
|
@Column(DataType.TEXT)
|
||||||
body: string;
|
body: string;
|
||||||
|
|
||||||
@Column
|
|
||||||
phoneNumberId: string;
|
|
||||||
|
|
||||||
@Column(DataType.STRING)
|
@Column(DataType.STRING)
|
||||||
get mediaUrl(): string | null {
|
get mediaUrl(): string | null {
|
||||||
if (this.getDataValue("mediaUrl")) {
|
if (this.getDataValue("mediaUrl")) {
|
||||||
return `${process.env.BACKEND_URL}:${
|
return `${process.env.BACKEND_URL}:${process.env.PROXY_PORT}/public/${this.getDataValue("mediaUrl")}`;
|
||||||
process.env.PROXY_PORT
|
|
||||||
}/public/${this.getDataValue("mediaUrl")}`;
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,9 +30,6 @@ class SettingTicket extends Model<SettingTicket> {
|
||||||
@Column
|
@Column
|
||||||
key: string;
|
key: string;
|
||||||
|
|
||||||
@Column
|
|
||||||
number: string;
|
|
||||||
|
|
||||||
@CreatedAt
|
@CreatedAt
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
|
|
||||||
|
|
|
@ -45,9 +45,6 @@ class Ticket extends Model<Ticket> {
|
||||||
@Column
|
@Column
|
||||||
statusChatEnd: string;
|
statusChatEnd: string;
|
||||||
|
|
||||||
@Column
|
|
||||||
phoneNumberId: string;
|
|
||||||
|
|
||||||
@CreatedAt
|
@CreatedAt
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
|
|
||||||
|
|
|
@ -42,9 +42,6 @@ class User extends Model<User> {
|
||||||
@Column
|
@Column
|
||||||
tokenVersion: number;
|
tokenVersion: number;
|
||||||
|
|
||||||
@Column
|
|
||||||
positionCompany: string;
|
|
||||||
|
|
||||||
@Default("admin")
|
@Default("admin")
|
||||||
@Column
|
@Column
|
||||||
profile: string;
|
profile: string;
|
||||||
|
@ -54,6 +51,7 @@ class User extends Model<User> {
|
||||||
|
|
||||||
@UpdatedAt
|
@UpdatedAt
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
|
|
||||||
@HasMany(() => Ticket)
|
@HasMany(() => Ticket)
|
||||||
tickets: Ticket[];
|
tickets: Ticket[];
|
||||||
|
|
||||||
|
|
|
@ -62,20 +62,6 @@ class Whatsapp extends Model<Whatsapp> {
|
||||||
@Column
|
@Column
|
||||||
urlApi: string;
|
urlApi: string;
|
||||||
|
|
||||||
@Column
|
|
||||||
phoneNumberId: string;
|
|
||||||
|
|
||||||
@Column
|
|
||||||
classification: string;
|
|
||||||
|
|
||||||
@Column
|
|
||||||
wabaId: string;
|
|
||||||
|
|
||||||
@Default(false)
|
|
||||||
@AllowNull
|
|
||||||
@Column
|
|
||||||
isOfficial: boolean;
|
|
||||||
|
|
||||||
@Default(false)
|
@Default(false)
|
||||||
@AllowNull
|
@AllowNull
|
||||||
@Column
|
@Column
|
||||||
|
|
|
@ -11,6 +11,6 @@ authRoutes.post("/login", SessionController.store);
|
||||||
|
|
||||||
authRoutes.post("/refresh_token", SessionController.update);
|
authRoutes.post("/refresh_token", SessionController.update);
|
||||||
|
|
||||||
authRoutes.delete("/logout/:userId", isAuth, SessionController.remove);
|
authRoutes.delete("/logout", isAuth, SessionController.remove);
|
||||||
|
|
||||||
export default authRoutes;
|
export default authRoutes;
|
||||||
|
|
|
@ -9,8 +9,6 @@ queueRoutes.get("/queue", isAuth, QueueController.index);
|
||||||
|
|
||||||
queueRoutes.post("/queue", isAuth, QueueController.store);
|
queueRoutes.post("/queue", isAuth, QueueController.store);
|
||||||
|
|
||||||
queueRoutes.post("/queue/customization", QueueController.customization);
|
|
||||||
|
|
||||||
queueRoutes.get("/queue/:queueId", isAuth, QueueController.show);
|
queueRoutes.get("/queue/:queueId", isAuth, QueueController.show);
|
||||||
|
|
||||||
queueRoutes.put("/queue/:queueId", isAuth, QueueController.update);
|
queueRoutes.put("/queue/:queueId", isAuth, QueueController.update);
|
||||||
|
|
|
@ -7,8 +7,6 @@ const settingRoutes = Router();
|
||||||
|
|
||||||
settingRoutes.get("/settings", SettingController.index);
|
settingRoutes.get("/settings", SettingController.index);
|
||||||
|
|
||||||
settingRoutes.get("/settings/ticket/:number", SettingController.ticketSettings);
|
|
||||||
|
|
||||||
// routes.get("/settings/:settingKey", isAuth, SettingsController.show);
|
// routes.get("/settings/:settingKey", isAuth, SettingsController.show);
|
||||||
|
|
||||||
settingRoutes.put(
|
settingRoutes.put(
|
||||||
|
|
|
@ -5,26 +5,12 @@ import * as WhatsAppController from "../controllers/WhatsAppController";
|
||||||
|
|
||||||
const whatsappRoutes = express.Router();
|
const whatsappRoutes = express.Router();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
whatsappRoutes.get("/whatsapp/", isAuth, WhatsAppController.index);
|
whatsappRoutes.get("/whatsapp/", isAuth, WhatsAppController.index);
|
||||||
|
|
||||||
whatsappRoutes.post("/whatsapp/", isAuth, WhatsAppController.store);
|
whatsappRoutes.post("/whatsapp/", isAuth, WhatsAppController.store);
|
||||||
|
|
||||||
whatsappRoutes.get(
|
|
||||||
"/whatsapp/official/matchQueue",
|
|
||||||
WhatsAppController.whatsAppOfficialMatchQueue
|
|
||||||
);
|
|
||||||
|
|
||||||
whatsappRoutes.get(
|
|
||||||
"/whatsapp/official/matchQueueUser",
|
|
||||||
WhatsAppController.whatsAppOfficialMatchQueueUser
|
|
||||||
);
|
|
||||||
|
|
||||||
whatsappRoutes.get("/whatsapp/official/media/:filename", WhatsAppController.media);
|
|
||||||
|
|
||||||
whatsappRoutes.post("/whatsapp/webhook", WhatsAppController.weebhook);
|
|
||||||
|
|
||||||
whatsappRoutes.get("/whatsapp/webhook", WhatsAppController.weebhook);
|
|
||||||
|
|
||||||
whatsappRoutes.get("/whatsapp/:whatsappId", isAuth, WhatsAppController.show);
|
whatsappRoutes.get("/whatsapp/:whatsappId", isAuth, WhatsAppController.show);
|
||||||
|
|
||||||
whatsappRoutes.put("/whatsapp/:whatsappId", isAuth, WhatsAppController.update);
|
whatsappRoutes.put("/whatsapp/:whatsappId", isAuth, WhatsAppController.update);
|
||||||
|
|
|
@ -7,8 +7,6 @@ import User from "./models/User";
|
||||||
import Whatsapp from "./models/Whatsapp";
|
import Whatsapp from "./models/Whatsapp";
|
||||||
import endPointQuery from "./helpers/EndPointQuery";
|
import endPointQuery from "./helpers/EndPointQuery";
|
||||||
import { cacheSize, flushCache, loadTicketsCache } from "./helpers/TicketCache";
|
import { cacheSize, flushCache, loadTicketsCache } from "./helpers/TicketCache";
|
||||||
|
|
||||||
import "./helpers/CloseBotTickets";
|
|
||||||
import { loadContactsCache } from "./helpers/ContactsCache";
|
import { loadContactsCache } from "./helpers/ContactsCache";
|
||||||
import { loadSchedulesCache } from "./helpers/SchedulingNotifyCache";
|
import { loadSchedulesCache } from "./helpers/SchedulingNotifyCache";
|
||||||
import { delRestoreControllFile } from "./helpers/RestoreControll";
|
import { delRestoreControllFile } from "./helpers/RestoreControll";
|
||||||
|
@ -45,17 +43,13 @@ gracefulShutdown(server);
|
||||||
|
|
||||||
loadSettings();
|
loadSettings();
|
||||||
|
|
||||||
let whatsapps: any = await Whatsapp.findAll({
|
let whatsapps: any = await Whatsapp.findAll({ attributes: ["id", "url"] });
|
||||||
attributes: ["id", "url", "phoneNumberId"]
|
|
||||||
});
|
// console.log('whatsapps: ', whatsapps)
|
||||||
|
|
||||||
if (whatsapps && whatsapps.length > 0) {
|
if (whatsapps && whatsapps.length > 0) {
|
||||||
for (let i = 0; i < whatsapps.length; i++) {
|
for (let i = 0; i < whatsapps.length; i++) {
|
||||||
try {
|
try {
|
||||||
const { phoneNumberId } = whatsapps[i];
|
|
||||||
|
|
||||||
if (phoneNumberId) continue;
|
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
`API URL: ${whatsapps[i].dataValues.url}/api/connection/status`
|
`API URL: ${whatsapps[i].dataValues.url}/api/connection/status`
|
||||||
);
|
);
|
||||||
|
|
|
@ -18,59 +18,73 @@ interface Request {
|
||||||
messageData: MessageData;
|
messageData: MessageData;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CreateMessageService = async ({
|
const CreateMessageService = async ({ messageData }: Request): Promise<Message> => {
|
||||||
messageData
|
|
||||||
}: Request): Promise<Message> => {
|
// console.log('UPSERT MESSAGE messageData: ', messageData)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
await Message.upsert(messageData);
|
await Message.upsert(messageData);
|
||||||
|
|
||||||
const message = await Message.findByPk(messageData.id, {
|
const message = await Message.findByPk(messageData.id, {
|
||||||
include: [
|
include: [
|
||||||
"contact",
|
"contact",
|
||||||
{
|
{
|
||||||
model: Ticket,
|
model: Ticket,
|
||||||
as: "ticket",
|
as: "ticket",
|
||||||
include: ["contact", "queue"]
|
include: ["contact", "queue"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
model: Message,
|
model: Message,
|
||||||
as: "quotedMsg",
|
as: "quotedMsg",
|
||||||
include: ["contact"]
|
include: ["contact"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!message) {
|
if (!message) {
|
||||||
throw new Error("ERR_CREATING_MESSAGE");
|
throw new Error("ERR_CREATING_MESSAGE");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.ticket.status != "queueChoice") {
|
|
||||||
await updateTicketCacheByTicketId(message.ticket.id, {
|
if (message.ticket.status != 'queueChoice') {
|
||||||
|
|
||||||
|
|
||||||
|
// TEST DEL
|
||||||
|
await updateTicketCacheByTicketId(message.ticket.id,
|
||||||
|
{
|
||||||
lastMessage: message.body,
|
lastMessage: message.body,
|
||||||
updatedAt: new Date(message.ticket.updatedAt).toISOString(),
|
updatedAt: new Date(message.ticket.updatedAt).toISOString(),
|
||||||
"contact.profilePicUrl": message.ticket.contact.profilePicUrl,
|
'contact.profilePicUrl': message.ticket.contact.profilePicUrl,
|
||||||
unreadMessages: message.ticket.unreadMessages
|
unreadMessages: message.ticket.unreadMessages
|
||||||
|
})
|
||||||
|
//
|
||||||
|
|
||||||
|
console.log('message.ticketId.toString(): ', message.ticketId.toString())
|
||||||
|
console.log('message.ticket.status: ',message.ticket.status)
|
||||||
|
|
||||||
|
const io = getIO();
|
||||||
|
io.to(message.ticketId.toString())
|
||||||
|
.to(message.ticket.status)
|
||||||
|
.to("notification")
|
||||||
|
.emit("appMessage", {
|
||||||
|
action: "create",
|
||||||
|
message,
|
||||||
|
ticket: message.ticket,
|
||||||
|
contact: message.ticket.contact
|
||||||
});
|
});
|
||||||
|
|
||||||
const io = getIO();
|
}
|
||||||
io.to(message.ticketId.toString())
|
|
||||||
.to(message.ticket.status)
|
|
||||||
.to("notification")
|
return message;
|
||||||
.emit("appMessage", {
|
|
||||||
action: "create",
|
|
||||||
message,
|
|
||||||
ticket: message.ticket,
|
|
||||||
contact: message.ticket.contact
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return message;
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error("===> Error on CreateMessageService.ts file: \n", error);
|
console.error('===> Error on CreateMessageService.ts file: \n', error)
|
||||||
throw new AppError(error.message);
|
throw new AppError(error.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CreateMessageService;
|
export default CreateMessageService;
|
||||||
|
|
|
@ -7,7 +7,6 @@ interface Request {
|
||||||
endTime: string;
|
endTime: string;
|
||||||
value: string;
|
value: string;
|
||||||
message: string;
|
message: string;
|
||||||
number: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateSettingTicket = async ({
|
const updateSettingTicket = async ({
|
||||||
|
@ -15,30 +14,16 @@ const updateSettingTicket = async ({
|
||||||
startTime,
|
startTime,
|
||||||
endTime,
|
endTime,
|
||||||
value,
|
value,
|
||||||
message,
|
message
|
||||||
number
|
|
||||||
}: Request): Promise<SettingTicket | undefined> => {
|
}: Request): Promise<SettingTicket | undefined> => {
|
||||||
try {
|
try {
|
||||||
let businessHours = await SettingTicket.findOne({ where: { key, number } });
|
const businessHours = await SettingTicket.findOne({ where: { key } });
|
||||||
|
|
||||||
if (!businessHours) {
|
if (!businessHours) {
|
||||||
// throw new AppError("ERR_NO_SETTING_FOUND", 404);
|
throw new AppError("ERR_NO_SETTING_FOUND", 404);
|
||||||
|
|
||||||
businessHours = await SettingTicket.create({
|
|
||||||
key,
|
|
||||||
startTime,
|
|
||||||
endTime,
|
|
||||||
value,
|
|
||||||
message,
|
|
||||||
number
|
|
||||||
});
|
|
||||||
return businessHours;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await businessHours.update(
|
await businessHours.update({ startTime, endTime, message, value });
|
||||||
{ startTime, endTime, message, value, number },
|
|
||||||
{ where: { key, number } }
|
|
||||||
);
|
|
||||||
|
|
||||||
return businessHours;
|
return businessHours;
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
|
|
|
@ -15,9 +15,6 @@ import TicketEmiterSumOpenClosedByUser from "../../helpers/OnlineReporEmiterInfo
|
||||||
import { createOrUpdateTicketCache } from "../../helpers/TicketCache";
|
import { createOrUpdateTicketCache } from "../../helpers/TicketCache";
|
||||||
import User from "../../models/User";
|
import User from "../../models/User";
|
||||||
import whatsappQueueMatchingUserQueue from "../../helpers/whatsappQueueMatchingUserQueue";
|
import whatsappQueueMatchingUserQueue from "../../helpers/whatsappQueueMatchingUserQueue";
|
||||||
import Whatsapp from "../../models/Whatsapp";
|
|
||||||
import ListWhatsAppsForQueueService from "../WhatsappService/ListWhatsAppsForQueueService";
|
|
||||||
import { json } from "sequelize";
|
|
||||||
let flatten = require("flat");
|
let flatten = require("flat");
|
||||||
|
|
||||||
interface Request {
|
interface Request {
|
||||||
|
@ -25,50 +22,18 @@ interface Request {
|
||||||
status: string;
|
status: string;
|
||||||
userId: number;
|
userId: number;
|
||||||
queueId?: number | undefined;
|
queueId?: number | undefined;
|
||||||
whatsappId?: number | string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const CreateTicketService = async ({
|
const CreateTicketService = async ({
|
||||||
contactId,
|
contactId,
|
||||||
status,
|
status,
|
||||||
userId,
|
userId,
|
||||||
queueId = undefined,
|
queueId = undefined
|
||||||
whatsappId
|
|
||||||
}: Request): Promise<Ticket> => {
|
}: Request): Promise<Ticket> => {
|
||||||
|
console.log("========> queueId: ", queueId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let defaultWhatsapp;
|
const defaultWhatsapp = await GetDefaultWhatsApp(userId);
|
||||||
|
|
||||||
if (whatsappId) {
|
|
||||||
defaultWhatsapp = await Whatsapp.findByPk(whatsappId);
|
|
||||||
} else {
|
|
||||||
defaultWhatsapp = await GetDefaultWhatsApp({ userId, queueId });
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (queueId) {
|
|
||||||
// const whatsappsByQueue = await ListWhatsAppsForQueueService(queueId);
|
|
||||||
|
|
||||||
// const exist = await CheckContactOpenTickets(
|
|
||||||
// contactId,
|
|
||||||
// defaultWhatsapp.id,
|
|
||||||
// true
|
|
||||||
// );
|
|
||||||
|
|
||||||
// console.log(
|
|
||||||
// "whatsappsByQueue: ",
|
|
||||||
// JSON.stringify(whatsappsByQueue, null, 6)
|
|
||||||
// );
|
|
||||||
|
|
||||||
// if (exist) {
|
|
||||||
// console.log("kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk");
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return new Ticket();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// console.log(JSON.stringify(defaultWhatsapp, null, 2));
|
|
||||||
// throw new AppError("test error");
|
|
||||||
|
|
||||||
const { phoneNumberId } = defaultWhatsapp;
|
|
||||||
|
|
||||||
const user = await User.findByPk(userId, { raw: true });
|
const user = await User.findByPk(userId, { raw: true });
|
||||||
|
|
||||||
|
@ -82,13 +47,6 @@ const CreateTicketService = async ({
|
||||||
queueId = matchingQueue ? matchingQueue.queueId : undefined;
|
queueId = matchingQueue ? matchingQueue.queueId : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(
|
|
||||||
"xxxxxxxxxxxx contactId: ",
|
|
||||||
contactId,
|
|
||||||
" | defaultWhatsapp.id: ",
|
|
||||||
defaultWhatsapp.id
|
|
||||||
);
|
|
||||||
|
|
||||||
await CheckContactOpenTickets(contactId, defaultWhatsapp.id);
|
await CheckContactOpenTickets(contactId, defaultWhatsapp.id);
|
||||||
|
|
||||||
const { isGroup } = await ShowContactService(contactId);
|
const { isGroup } = await ShowContactService(contactId);
|
||||||
|
@ -98,8 +56,7 @@ const CreateTicketService = async ({
|
||||||
status,
|
status,
|
||||||
isGroup,
|
isGroup,
|
||||||
userId,
|
userId,
|
||||||
queueId,
|
queueId
|
||||||
phoneNumberId
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const ticket = await Ticket.findByPk(id, { include: ["contact"] });
|
const ticket = await Ticket.findByPk(id, { include: ["contact"] });
|
||||||
|
|
|
@ -13,15 +13,11 @@ const FindOrCreateTicketService = async (
|
||||||
contact: Contact,
|
contact: Contact,
|
||||||
whatsappId: number,
|
whatsappId: number,
|
||||||
unreadMessages: number,
|
unreadMessages: number,
|
||||||
groupContact?: Contact,
|
groupContact?: Contact
|
||||||
): Promise<Ticket> => {
|
): Promise<Ticket> => {
|
||||||
try {
|
try {
|
||||||
let ticket;
|
let ticket;
|
||||||
|
|
||||||
// else if (getSettingValue("whatsaAppCloudApi")?.value == "enabled") {
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (getSettingValue("oneContactChatWithManyWhats")?.value == "enabled") {
|
if (getSettingValue("oneContactChatWithManyWhats")?.value == "enabled") {
|
||||||
let whats = await ListWhatsAppsNumber(whatsappId);
|
let whats = await ListWhatsAppsNumber(whatsappId);
|
||||||
|
|
||||||
|
@ -45,8 +41,10 @@ const FindOrCreateTicketService = async (
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { queues, greetingMessage, phoneNumberId } = await ShowWhatsAppService(whatsappId);
|
const { queues, greetingMessage } = await ShowWhatsAppService(whatsappId);
|
||||||
|
|
||||||
|
//Habilitar esse caso queira usar o bot
|
||||||
|
// const botInfo = await BotIsOnQueue('botqueue')
|
||||||
const botInfo = { isOnQueue: false };
|
const botInfo = { isOnQueue: false };
|
||||||
|
|
||||||
if (ticket) {
|
if (ticket) {
|
||||||
|
@ -74,6 +72,8 @@ const FindOrCreateTicketService = async (
|
||||||
ticket = await Ticket.findOne({
|
ticket = await Ticket.findOne({
|
||||||
where: {
|
where: {
|
||||||
updatedAt: {
|
updatedAt: {
|
||||||
|
//[Op.between]: [+subHours(new Date(), 2), +new Date()]
|
||||||
|
|
||||||
// Tempo osioso para a ura responder thuanny
|
// Tempo osioso para a ura responder thuanny
|
||||||
//[Op.between]: [+subMinutes(new Date(), 30), +new Date()]
|
//[Op.between]: [+subMinutes(new Date(), 30), +new Date()]
|
||||||
|
|
||||||
|
@ -106,9 +106,15 @@ const FindOrCreateTicketService = async (
|
||||||
status: status,
|
status: status,
|
||||||
isGroup: !!groupContact,
|
isGroup: !!groupContact,
|
||||||
unreadMessages,
|
unreadMessages,
|
||||||
whatsappId,
|
whatsappId
|
||||||
phoneNumberId
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TEST DEL
|
||||||
|
|
||||||
|
// const { name } = await ShowContactService(contact.id);
|
||||||
|
// console.log('FIND OR CREATE TICKET SERVICE NAME: ', contact.name, ' STATUS: ', status)
|
||||||
|
|
||||||
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
ticket = await ShowTicketService(ticket.id);
|
ticket = await ShowTicketService(ticket.id);
|
||||||
|
|
|
@ -1,147 +0,0 @@
|
||||||
import { subHours, subMinutes, subSeconds } from "date-fns";
|
|
||||||
import { Op } from "sequelize";
|
|
||||||
import BotIsOnQueue from "../../helpers/BotIsOnQueue";
|
|
||||||
import Contact from "../../models/Contact";
|
|
||||||
import Ticket from "../../models/Ticket";
|
|
||||||
import ShowWhatsAppService from "../WhatsappService/ShowWhatsAppService";
|
|
||||||
import ShowTicketService from "./ShowTicketService";
|
|
||||||
import AppError from "../../errors/AppError";
|
|
||||||
import { userInfo } from "os";
|
|
||||||
import ShowQueueService from "../QueueService/ShowQueueService";
|
|
||||||
import UpdateTicketService from "./UpdateTicketService";
|
|
||||||
|
|
||||||
|
|
||||||
const FindOrCreateTicketServiceBot = async (
|
|
||||||
contact: Contact,
|
|
||||||
whatsappId: number,
|
|
||||||
unreadMessages: number,
|
|
||||||
groupContact?: Contact
|
|
||||||
): Promise<any> => {
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
let ticket = await Ticket.findOne({
|
|
||||||
where: {
|
|
||||||
status: {
|
|
||||||
[Op.or]: ["open", "pending", "queueChoice"]
|
|
||||||
},
|
|
||||||
contactId: groupContact ? groupContact.id : contact.id
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const { queues, greetingMessage } = await ShowWhatsAppService(whatsappId);
|
|
||||||
|
|
||||||
|
|
||||||
//Habilitar esse caso queira usar o bot
|
|
||||||
const botInfo = await BotIsOnQueue('botqueue')
|
|
||||||
// const botInfo = { isOnQueue: false }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (ticket) {
|
|
||||||
await ticket.update({ unreadMessages });
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (!ticket && groupContact) {
|
|
||||||
// ticket = await Ticket.findOne({
|
|
||||||
// where: {
|
|
||||||
// contactId: groupContact.id
|
|
||||||
// },
|
|
||||||
// order: [["updatedAt", "DESC"]]
|
|
||||||
// });
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// if (ticket) {
|
|
||||||
|
|
||||||
// await ticket.update({
|
|
||||||
// status: "pending",
|
|
||||||
// userId: null,
|
|
||||||
// unreadMessages
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (!ticket && !groupContact) {
|
|
||||||
|
|
||||||
console.log('BOT CREATING OR REOPENING THE TICKET')
|
|
||||||
|
|
||||||
ticket = await Ticket.findOne({
|
|
||||||
where: {
|
|
||||||
contactId: contact.id,
|
|
||||||
userId: botInfo.userIdBot
|
|
||||||
},
|
|
||||||
order: [["updatedAt", "DESC"]]
|
|
||||||
});
|
|
||||||
|
|
||||||
if (ticket) {
|
|
||||||
|
|
||||||
await ticket.update({
|
|
||||||
status: "open",
|
|
||||||
userId: botInfo.userIdBot,
|
|
||||||
unreadMessages
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('lxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')
|
|
||||||
|
|
||||||
await dialogFlowStartContext(contact, ticket, botInfo);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let created = false
|
|
||||||
|
|
||||||
if (!ticket) {
|
|
||||||
|
|
||||||
created = true
|
|
||||||
|
|
||||||
let status = "open"
|
|
||||||
|
|
||||||
if (queues.length > 1 && !botInfo.isOnQueue) {
|
|
||||||
status = "queueChoice"
|
|
||||||
}
|
|
||||||
|
|
||||||
ticket = await Ticket.create({
|
|
||||||
contactId: groupContact ? groupContact.id : contact.id,
|
|
||||||
status: status,
|
|
||||||
userId: botInfo.userIdBot,
|
|
||||||
isGroup: !!groupContact,
|
|
||||||
unreadMessages,
|
|
||||||
whatsappId
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy')
|
|
||||||
|
|
||||||
await dialogFlowStartContext(contact, ticket, botInfo);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ticket = await ShowTicketService(ticket.id);
|
|
||||||
|
|
||||||
return { ticket, created };
|
|
||||||
|
|
||||||
} catch (error: any) {
|
|
||||||
console.error('===> Error on FindOrCreateTicketServiceBot.ts file: \n', error)
|
|
||||||
throw new AppError(error.message);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default FindOrCreateTicketServiceBot;
|
|
||||||
|
|
||||||
async function dialogFlowStartContext(contact: Contact, ticket: Ticket, botInfo: any) {
|
|
||||||
|
|
||||||
let msg: any = { type: 'chat', from: `${contact.number}@c.us`, body: '0' };
|
|
||||||
|
|
||||||
let queue = await ShowQueueService(botInfo.botQueueId);
|
|
||||||
|
|
||||||
await UpdateTicketService({
|
|
||||||
ticketData: { queueId: queue.id },
|
|
||||||
ticketId: ticket.id
|
|
||||||
});
|
|
||||||
|
|
||||||
ticket = await ShowTicketService(ticket.id);
|
|
||||||
|
|
||||||
// await sendDialogflowAnswer(ticket.whatsappId, ticket, msg, contact, false);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,60 +1,47 @@
|
||||||
import { Sequelize } from "sequelize";
|
|
||||||
|
import { Sequelize, } from "sequelize";
|
||||||
|
|
||||||
const dbConfig = require("../../config/database");
|
const dbConfig = require("../../config/database");
|
||||||
const sequelize = new Sequelize(dbConfig);
|
const sequelize = new Sequelize(dbConfig);
|
||||||
const { QueryTypes } = require("sequelize");
|
const { QueryTypes } = require('sequelize');
|
||||||
|
|
||||||
import { splitDateTime } from "../../helpers/SplitDateTime";
|
import { splitDateTime } from "../../helpers/SplitDateTime";
|
||||||
import format from "date-fns/format";
|
import format from 'date-fns/format';
|
||||||
import ptBR from "date-fns/locale/pt-BR";
|
import ptBR from 'date-fns/locale/pt-BR';
|
||||||
|
|
||||||
|
|
||||||
interface Request {
|
interface Request {
|
||||||
timeseconds: string | number;
|
timeseconds: string | number;
|
||||||
status: string;
|
status: string;
|
||||||
number?: string;
|
userId?: string | number;
|
||||||
userId?: string | number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ListTicketTimeLife = async ({
|
const ListTicketTimeLife = async ({timeseconds, status, userId }: Request): Promise<any[]> => {
|
||||||
timeseconds,
|
|
||||||
status,
|
|
||||||
number,
|
|
||||||
userId
|
|
||||||
}: Request): Promise<any[]> => {
|
|
||||||
let tickets = [];
|
|
||||||
|
|
||||||
let currentDate = format(new Date(), "yyyy-MM-dd HH:mm:ss", { locale: ptBR });
|
let tickets = []
|
||||||
|
|
||||||
// console.log('------------------> currentDate: ', currentDate)
|
let currentDate = format(new Date(), 'yyyy-MM-dd HH:mm:ss', { locale: ptBR })
|
||||||
|
|
||||||
if (userId) {
|
// console.log('------------------> currentDate: ', currentDate)
|
||||||
// CONSULTANDO FILAS PELO ID DO USUARIO
|
|
||||||
tickets = await sequelize.query(
|
|
||||||
`select user.id as user_id, user.name as user_name, t.id as ticket_id from Tickets as t inner join Users as user on
|
|
||||||
t.userId = user.id and user.name = 'botqueue' and t.status='${status}' and (TIMESTAMPDIFF(SECOND, t.updatedAt, '${currentDate}')) >= ${timeseconds};`,
|
|
||||||
{ type: QueryTypes.SELECT }
|
|
||||||
);
|
|
||||||
} else if (number) {
|
|
||||||
// CONSULTANDO TICKETS PELO WHATSAPP
|
|
||||||
tickets = await sequelize.query(
|
|
||||||
`SELECT t.id AS ticket_id
|
|
||||||
FROM Tickets t
|
|
||||||
JOIN Whatsapps w ON t.whatsappId = w.id
|
|
||||||
AND w.number = ${number}
|
|
||||||
WHERE t.status = 'open'
|
|
||||||
AND TIMESTAMPDIFF(SECOND, t.updatedAt, '${currentDate}') >= ${timeseconds};`,
|
|
||||||
{ type: QueryTypes.SELECT }
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// CONSULTANDO FILAS PELO USUARIO
|
|
||||||
tickets = await sequelize.query(
|
|
||||||
`select id as ticket_id from Tickets where status='${status}' and
|
|
||||||
(TIMESTAMPDIFF(SECOND, updatedAt, '${currentDate}')) >= ${timeseconds};`,
|
|
||||||
{ type: QueryTypes.SELECT }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return tickets;
|
if (userId) {
|
||||||
|
// CONSULTANDO FILAS PELO ID DO USUARIO
|
||||||
|
tickets = await sequelize.query(`select user.id as user_id, user.name as user_name, t.id as ticket_id from Tickets as t inner join Users as user on
|
||||||
|
t.userId = user.id and user.name = 'botqueue' and t.status='${status}' and (TIMESTAMPDIFF(SECOND, t.updatedAt, '${currentDate}')) >= ${timeseconds};`, { type: QueryTypes.SELECT });
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// CONSULTANDO FILAS PELO USUARIO
|
||||||
|
tickets = await sequelize.query(`select id as ticket_id from Tickets where status='${status}' and
|
||||||
|
(TIMESTAMPDIFF(SECOND, updatedAt, '${currentDate}')) >= ${timeseconds};`, { type: QueryTypes.SELECT });
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return tickets;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ListTicketTimeLife;
|
export default ListTicketTimeLife;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -194,12 +194,8 @@ const ListTicketsService = async ({
|
||||||
|
|
||||||
const userProfile: any = await User.findByPk(userId)
|
const userProfile: any = await User.findByPk(userId)
|
||||||
|
|
||||||
if (
|
if (userProfile.dataValues.profile != 'admin' && userProfile.dataValues.profile != 'master') {
|
||||||
userProfile.dataValues.profile != "admin" &&
|
whereCondition = { ...whereCondition, userId }
|
||||||
userProfile.dataValues.profile != "master"
|
|
||||||
// userProfile.dataValues.profile != "supervisor"
|
|
||||||
) {
|
|
||||||
whereCondition = { ...whereCondition, userId };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,6 @@ import ShowTicketService from "./ShowTicketService";
|
||||||
import { createOrUpdateTicketCache } from "../../helpers/TicketCache";
|
import { createOrUpdateTicketCache } from "../../helpers/TicketCache";
|
||||||
import AppError from "../../errors/AppError";
|
import AppError from "../../errors/AppError";
|
||||||
import sendWhatsAppMessageSocket from "../../helpers/SendWhatsappMessageSocket";
|
import sendWhatsAppMessageSocket from "../../helpers/SendWhatsappMessageSocket";
|
||||||
import BotIsOnQueue from "../../helpers/BotIsOnQueue";
|
|
||||||
import { deleteObject } from "../../helpers/RedisClient"
|
|
||||||
var flatten = require("flat");
|
var flatten = require("flat");
|
||||||
|
|
||||||
interface TicketData {
|
interface TicketData {
|
||||||
|
@ -50,15 +48,7 @@ const UpdateTicketService = async ({
|
||||||
} = ticketData;
|
} = ticketData;
|
||||||
|
|
||||||
const ticket = await ShowTicketService(ticketId);
|
const ticket = await ShowTicketService(ticketId);
|
||||||
|
// await SetTicketMessagesAsRead(ticket);
|
||||||
const botInfo = await BotIsOnQueue("botqueue");
|
|
||||||
|
|
||||||
if (
|
|
||||||
status == "closed" ||
|
|
||||||
(status == "open" && ticket && `${userId}` != `${botInfo.userIdBot}`)
|
|
||||||
) {
|
|
||||||
deleteObject(`${ticket.whatsappId}`, `${ticket.contactId}`, "ura");
|
|
||||||
}
|
|
||||||
|
|
||||||
const oldStatus = ticket.status;
|
const oldStatus = ticket.status;
|
||||||
const oldUserId = ticket.user?.id;
|
const oldUserId = ticket.user?.id;
|
||||||
|
@ -79,6 +69,7 @@ const UpdateTicketService = async ({
|
||||||
await ticket.reload();
|
await ticket.reload();
|
||||||
|
|
||||||
if (msg?.trim().length > 0) {
|
if (msg?.trim().length > 0) {
|
||||||
|
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
sendWhatsAppMessageSocket(ticket, msg);
|
sendWhatsAppMessageSocket(ticket, msg);
|
||||||
}, 2000);
|
}, 2000);
|
||||||
|
|
|
@ -10,7 +10,6 @@ import Queue from "../../models/Queue";
|
||||||
interface SerializedUser {
|
interface SerializedUser {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
positionCompany: string;
|
|
||||||
email: string;
|
email: string;
|
||||||
profile: string;
|
profile: string;
|
||||||
queues: Queue[];
|
queues: Queue[];
|
||||||
|
|
|
@ -8,7 +8,6 @@ interface Request {
|
||||||
email: string;
|
email: string;
|
||||||
password: string;
|
password: string;
|
||||||
name: string;
|
name: string;
|
||||||
positionCompany?: string;
|
|
||||||
queueIds?: number[];
|
queueIds?: number[];
|
||||||
profile?: string;
|
profile?: string;
|
||||||
}
|
}
|
||||||
|
@ -16,7 +15,6 @@ interface Request {
|
||||||
interface Response {
|
interface Response {
|
||||||
email: string;
|
email: string;
|
||||||
name: string;
|
name: string;
|
||||||
positionCompany: string;
|
|
||||||
id: number;
|
id: number;
|
||||||
profile: string;
|
profile: string;
|
||||||
}
|
}
|
||||||
|
@ -25,7 +23,6 @@ const CreateUserService = async ({
|
||||||
email,
|
email,
|
||||||
password,
|
password,
|
||||||
name,
|
name,
|
||||||
positionCompany,
|
|
||||||
queueIds = [],
|
queueIds = [],
|
||||||
profile = "master"
|
profile = "master"
|
||||||
}: Request): Promise<Response> => {
|
}: Request): Promise<Response> => {
|
||||||
|
@ -73,7 +70,6 @@ const CreateUserService = async ({
|
||||||
email,
|
email,
|
||||||
password,
|
password,
|
||||||
name,
|
name,
|
||||||
positionCompany,
|
|
||||||
profile
|
profile
|
||||||
},
|
},
|
||||||
{ include: ["queues"] }
|
{ include: ["queues"] }
|
||||||
|
|
|
@ -2,7 +2,7 @@ import User from "../../models/User";
|
||||||
import AppError from "../../errors/AppError";
|
import AppError from "../../errors/AppError";
|
||||||
import Ticket from "../../models/Ticket";
|
import Ticket from "../../models/Ticket";
|
||||||
import UpdateDeletedUserOpenTicketsStatus from "../../helpers/UpdateDeletedUserOpenTicketsStatus";
|
import UpdateDeletedUserOpenTicketsStatus from "../../helpers/UpdateDeletedUserOpenTicketsStatus";
|
||||||
import { set } from "../../helpers/RedisClient"
|
|
||||||
|
|
||||||
const DeleteUserService = async (id: string | number): Promise<void> => {
|
const DeleteUserService = async (id: string | number): Promise<void> => {
|
||||||
const user = await User.findOne({
|
const user = await User.findOne({
|
||||||
|
@ -13,17 +13,6 @@ const DeleteUserService = async (id: string | number): Promise<void> => {
|
||||||
throw new AppError("ERR_NO_USER_FOUND", 404);
|
throw new AppError("ERR_NO_USER_FOUND", 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user?.name?.trim() == "botqueue") {
|
|
||||||
let botInfo = JSON.stringify({
|
|
||||||
userId: 0,
|
|
||||||
queueId: 0,
|
|
||||||
botIsOnQueue: false
|
|
||||||
});
|
|
||||||
botInfo = JSON.parse(botInfo);
|
|
||||||
|
|
||||||
await set("botInfo", botInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
const userOpenTickets: Ticket[] = await user.$get("tickets", {
|
const userOpenTickets: Ticket[] = await user.$get("tickets", {
|
||||||
where: { status: "open" }
|
where: { status: "open" }
|
||||||
});
|
});
|
||||||
|
@ -32,7 +21,9 @@ const DeleteUserService = async (id: string | number): Promise<void> => {
|
||||||
UpdateDeletedUserOpenTicketsStatus(userOpenTickets);
|
UpdateDeletedUserOpenTicketsStatus(userOpenTickets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
await user.destroy();
|
await user.destroy();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DeleteUserService;
|
export default DeleteUserService;
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
import { Sequelize } from "sequelize";
|
|
||||||
import Whatsapp from "../../models/Whatsapp";
|
|
||||||
import WhatsappQueue from "../../models/WhatsappQueue";
|
|
||||||
import { List } from "whatsapp-web.js";
|
|
||||||
const dbConfig = require("../../config/database");
|
|
||||||
const { QueryTypes } = require("sequelize");
|
|
||||||
|
|
||||||
const sequelize = new Sequelize(dbConfig);
|
|
||||||
|
|
||||||
const ListWhatsappQueueByUserQueue = async (
|
|
||||||
userId: number | string,
|
|
||||||
profiles: string
|
|
||||||
): Promise<any> => {
|
|
||||||
const users = await sequelize.query(
|
|
||||||
`select wq.whatsappId, wq.queueId, uq.userId, uq.queueId, u.id, u.name, u.profile, w.number
|
|
||||||
from WhatsappQueues wq join UserQueues uq join Users u join Whatsapps w on
|
|
||||||
wq.queueId = uq.queueId where u.id = uq.userId and u.profile in (${profiles}) and u.id = ${userId}
|
|
||||||
and w.id = wq.whatsappId group by w.number ;`,
|
|
||||||
{ type: QueryTypes.SELECT }
|
|
||||||
);
|
|
||||||
|
|
||||||
return users;
|
|
||||||
};
|
|
||||||
|
|
||||||
const ListWhatsappQueesByUser = async (whatsappIds: string): Promise<any> => {
|
|
||||||
const users = await sequelize.query(
|
|
||||||
`SELECT
|
|
||||||
wq.whatsappId, wq.queueId, q.name, q.id, q.name, q.color
|
|
||||||
FROM
|
|
||||||
WhatsappQueues wq
|
|
||||||
JOIN
|
|
||||||
Queues q ON wq.whatsappId IN (${whatsappIds}) AND q.id = wq.queueId group by wq.queueId;
|
|
||||||
|
|
||||||
`,
|
|
||||||
{ type: QueryTypes.SELECT }
|
|
||||||
);
|
|
||||||
|
|
||||||
return users;
|
|
||||||
};
|
|
||||||
|
|
||||||
const ListUserByWhatsappQueuesService = async (
|
|
||||||
userId: number | string,
|
|
||||||
profiles: string
|
|
||||||
): Promise<any> => {
|
|
||||||
const whatsapps: any = await ListWhatsappQueueByUserQueue(userId, profiles);
|
|
||||||
|
|
||||||
let whatsappIds = whatsapps.map((w: any) => w.whatsappId);
|
|
||||||
|
|
||||||
if (whatsappIds.length == 0) return { users: [], queues: [] };
|
|
||||||
|
|
||||||
console.log("----------> whatsappIds: ", whatsappIds, " | userId: ", userId);
|
|
||||||
|
|
||||||
whatsappIds = whatsappIds.join(", ");
|
|
||||||
|
|
||||||
const users: any = await sequelize.query(
|
|
||||||
`select wq.whatsappId, wq.queueId, uq.userId, uq.queueId, u.id, u.name, u.profile
|
|
||||||
from WhatsappQueues wq join UserQueues uq join Users u on
|
|
||||||
wq.queueId = uq.queueId where u.id = uq.userId and u.profile in (${profiles}) and wq.whatsappId in (${whatsappIds}) group by u.id;`,
|
|
||||||
{ type: QueryTypes.SELECT }
|
|
||||||
);
|
|
||||||
|
|
||||||
const queues = await ListWhatsappQueesByUser(whatsappIds);
|
|
||||||
|
|
||||||
return { users, queues };
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ListUserByWhatsappQueuesService;
|
|
|
@ -1,56 +1,77 @@
|
||||||
|
|
||||||
import { Op, Sequelize } from "sequelize";
|
import { Op, Sequelize } from "sequelize";
|
||||||
import Queue from "../../models/Queue";
|
import Queue from "../../models/Queue";
|
||||||
import User from "../../models/User";
|
import User from "../../models/User";
|
||||||
import UserQueue from "../../models/UserQueue";
|
import UserQueue from "../../models/UserQueue";
|
||||||
import { List } from "whatsapp-web.js"
|
|
||||||
|
|
||||||
interface Request {
|
interface Request {
|
||||||
userId?: string | number;
|
userId?: string | number;
|
||||||
profile?: string;
|
profile?: string;
|
||||||
profiles?: Array<string>;
|
raw?:boolean
|
||||||
raw?: boolean;
|
|
||||||
userIds?: string | number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ListUser = async ({ profile, userId, raw, userIds, profiles }: Request): Promise<User[]> => {
|
|
||||||
let where_clause = {};
|
const ListUser = async ({ profile, userId, raw}: Request): Promise<User[]> => {
|
||||||
|
|
||||||
|
let where_clause = {}
|
||||||
|
|
||||||
if (userId && profile) {
|
if (userId && profile) {
|
||||||
where_clause = {
|
where_clause = {
|
||||||
[Op.and]: [{ userId: userId }, { profile: profile }]
|
[Op.and]: [
|
||||||
};
|
{ userId: userId },
|
||||||
} else if (userId) {
|
{ profile: profile }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (userId) {
|
||||||
where_clause = {
|
where_clause = {
|
||||||
[Op.and]: [{ userId: userId }]
|
[Op.and]: [
|
||||||
};
|
{ userId: userId },
|
||||||
} else if (profile) {
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (profile) {
|
||||||
where_clause = {
|
where_clause = {
|
||||||
profile: profile
|
profile: profile
|
||||||
};
|
}
|
||||||
} else if (userIds) {
|
|
||||||
where_clause = {
|
|
||||||
id: { [Op.in]: userIds }
|
|
||||||
};
|
|
||||||
} else if (profiles) {
|
|
||||||
where_clause = {
|
|
||||||
profile: { [Op.in]: profiles }
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const users = await User.findAll({
|
|
||||||
|
const queryOptions:any = {
|
||||||
where: where_clause,
|
where: where_clause,
|
||||||
raw,
|
raw,
|
||||||
attributes: ["id", "name", "email", "positionCompany"],
|
attributes: ["id", "name", "email"],
|
||||||
|
order: [["id", "ASC"]]
|
||||||
|
};
|
||||||
|
|
||||||
include: [
|
if (!raw) {
|
||||||
|
queryOptions.include = [
|
||||||
{ model: Queue, as: "queues", attributes: ["id", "name", "color"] }
|
{ model: Queue, as: "queues", attributes: ["id", "name", "color"] }
|
||||||
],
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
const users = await User.findAll(queryOptions);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// const users = await User.findAll({
|
||||||
|
// where: where_clause,
|
||||||
|
// raw,
|
||||||
|
// attributes: ['id', 'name', 'email'],
|
||||||
|
|
||||||
|
// include: [
|
||||||
|
// { model: Queue, as: "queues", attributes: ["id", "name", "color"] }
|
||||||
|
// ],
|
||||||
|
|
||||||
|
// order: [["id", "ASC"]],
|
||||||
|
// })
|
||||||
|
|
||||||
order: [["id", "ASC"]],
|
|
||||||
group: ["User.id"]
|
|
||||||
});
|
|
||||||
|
|
||||||
return users;
|
return users;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ListUser;
|
export default ListUser;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ const ListUsersService = async ({
|
||||||
|
|
||||||
const { count, rows: users } = await User.findAndCountAll({
|
const { count, rows: users } = await User.findAndCountAll({
|
||||||
where: whereCondition,
|
where: whereCondition,
|
||||||
attributes: ["name", "id", "email","positionCompany", "profile", "createdAt"],
|
attributes: ["name", "id", "email", "profile", "createdAt"],
|
||||||
limit,
|
limit,
|
||||||
offset,
|
offset,
|
||||||
order: [["createdAt", "DESC"]],
|
order: [["createdAt", "DESC"]],
|
||||||
|
|
|
@ -4,7 +4,7 @@ import Queue from "../../models/Queue";
|
||||||
|
|
||||||
const ShowUserService = async (id: string | number): Promise<User> => {
|
const ShowUserService = async (id: string | number): Promise<User> => {
|
||||||
const user = await User.findByPk(id, {
|
const user = await User.findByPk(id, {
|
||||||
attributes: ["name", "id", "email", "profile", "positionCompany", "tokenVersion"],
|
attributes: ["name", "id", "email", "profile", "tokenVersion"],
|
||||||
include: [
|
include: [
|
||||||
{ model: Queue, as: "queues", attributes: ["id", "name", "color"] }
|
{ model: Queue, as: "queues", attributes: ["id", "name", "color"] }
|
||||||
],
|
],
|
||||||
|
|
|
@ -8,7 +8,6 @@ interface UserData {
|
||||||
email?: string;
|
email?: string;
|
||||||
password?: string;
|
password?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
positionCompany?: string;
|
|
||||||
profile?: string;
|
profile?: string;
|
||||||
queueIds?: number[];
|
queueIds?: number[];
|
||||||
}
|
}
|
||||||
|
@ -61,7 +60,7 @@ const UpdateUserService = async ({
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const { email, password, profile, name, positionCompany, queueIds = [] } = userData;
|
const { email, password, profile, name, queueIds = [] } = userData;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await schema.validate({ email, password, profile, name });
|
await schema.validate({ email, password, profile, name });
|
||||||
|
@ -74,7 +73,6 @@ const UpdateUserService = async ({
|
||||||
email,
|
email,
|
||||||
password,
|
password,
|
||||||
profile,
|
profile,
|
||||||
positionCompany,
|
|
||||||
name
|
name
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { getWbot } from "../../libs/wbot";
|
||||||
|
|
||||||
const CheckIsValidContact = async (number: string): Promise<any> => {
|
const CheckIsValidContact = async (number: string): Promise<any> => {
|
||||||
|
|
||||||
const defaultWhatsapp = await GetDefaultWhatsApp({});
|
const defaultWhatsapp = await GetDefaultWhatsApp();
|
||||||
|
|
||||||
const wbot_url = await getWbot(defaultWhatsapp.id);
|
const wbot_url = await getWbot(defaultWhatsapp.id);
|
||||||
|
|
||||||
|
|
|
@ -16,10 +16,6 @@ const DeleteWhatsAppMessage = async (messageId: string): Promise<Message | any>
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
if(message && message?.phoneNumberId){
|
|
||||||
throw new AppError("Mensagens enviada pela API Oficial do Whatsapp não são deletadas!");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!message) {
|
if (!message) {
|
||||||
throw new AppError("No message found with this ID.");
|
throw new AppError("No message found with this ID.");
|
||||||
}
|
}
|
||||||
|
@ -36,6 +32,18 @@ const DeleteWhatsAppMessage = async (messageId: string): Promise<Message | any>
|
||||||
limit: limit
|
limit: limit
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// console.log('messageToDelete.data.data: ',messageToDelete.data.data)
|
||||||
|
|
||||||
|
// const { ticket } = message;
|
||||||
|
|
||||||
|
// const messageToDelete = await GetWbotMessage(ticket, messageId);
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// await messageToDelete.delete(true);
|
||||||
|
// } catch (err) {
|
||||||
|
// throw new AppError("ERR_DELETE_WAPP_MSG");
|
||||||
|
// }
|
||||||
|
|
||||||
if (messageToDelete && messageToDelete.data.data) {
|
if (messageToDelete && messageToDelete.data.data) {
|
||||||
await message.update({ isDeleted: true });
|
await message.update({ isDeleted: true });
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,15 +4,19 @@ import { getWbot } from "../../libs/wbot";
|
||||||
|
|
||||||
const GetProfilePicUrl = async (number: string): Promise<any> => {
|
const GetProfilePicUrl = async (number: string): Promise<any> => {
|
||||||
|
|
||||||
const defaultWhatsapp = await GetDefaultWhatsApp({});
|
const defaultWhatsapp = await GetDefaultWhatsApp();
|
||||||
|
|
||||||
const wbot_url = await getWbot(defaultWhatsapp.id);
|
const wbot_url = await getWbot(defaultWhatsapp.id);
|
||||||
|
|
||||||
|
// const profilePicUrl = await wbot.getProfilePicUrl(`${number}@c.us`);
|
||||||
|
|
||||||
let profilePicUrl = await endPointQuery(`${wbot_url}/api/GetProfilePicUrl`, { number: `${number}`, })
|
let profilePicUrl = await endPointQuery(`${wbot_url}/api/GetProfilePicUrl`, { number: `${number}`, })
|
||||||
|
|
||||||
console.log('profilePicUrl.data.data: ', profilePicUrl.data.data)
|
console.log('profilePicUrl.data.data: ', profilePicUrl.data.data)
|
||||||
|
|
||||||
if (profilePicUrl && profilePicUrl.data.data) {
|
if (profilePicUrl && profilePicUrl.data.data) {
|
||||||
|
|
||||||
|
console.log('GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG')
|
||||||
return profilePicUrl.data.data;
|
return profilePicUrl.data.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,61 +4,47 @@ import AppError from "../../errors/AppError";
|
||||||
import GetTicketWbot from "../../helpers/GetTicketWbot";
|
import GetTicketWbot from "../../helpers/GetTicketWbot";
|
||||||
import Ticket from "../../models/Ticket";
|
import Ticket from "../../models/Ticket";
|
||||||
|
|
||||||
import { updateTicketCacheByTicketId } from "../../helpers/TicketCache";
|
import { updateTicketCacheByTicketId } from '../../helpers/TicketCache'
|
||||||
import { date } from "faker";
|
import { date } from "faker";
|
||||||
import { getIO } from "../../libs/socket";
|
import { getIO } from "../../libs/socket";
|
||||||
import sendWhatsAppMessageSocket from "../../helpers/SendWhatsappMessageSocket";
|
import sendWhatsAppMessageSocket from "../../helpers/SendWhatsappMessageSocket";
|
||||||
import sendWhatsAppMediaSocket from "../../helpers/SendWhatsappMessageMediaSocket";
|
import sendWhatsAppMediaSocket from "../../helpers/SendWhatsappMessageMediaSocket";
|
||||||
import sendWhatsMediaOfficialAPI from "../../helpers/sendWhatsMediaOfficialAPI";
|
|
||||||
import { mediaTypeWhatsappOfficial } from "./wbotMessageListener";
|
|
||||||
import { bytesToMB } from "../../helpers/BytesToMB";
|
|
||||||
|
|
||||||
interface Request {
|
interface Request {
|
||||||
media: Express.Multer.File;
|
media: Express.Multer.File;
|
||||||
ticket: Ticket;
|
ticket: Ticket;
|
||||||
mic_audio?: any
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const SendWhatsAppMedia = async ({
|
const SendWhatsAppMedia = async ({
|
||||||
media,
|
media,
|
||||||
ticket,
|
ticket
|
||||||
mic_audio
|
|
||||||
}: Request): Promise<WbotMessage | any> => {
|
}: Request): Promise<WbotMessage | any> => {
|
||||||
const { phoneNumberId } = ticket;
|
|
||||||
|
|
||||||
if (phoneNumberId) {
|
|
||||||
const { type, mbMaxSize }: any = mediaTypeWhatsappOfficial(media.mimetype);
|
|
||||||
|
|
||||||
const filesize: any = bytesToMB(media.size);
|
|
||||||
|
|
||||||
if (filesize > mbMaxSize) {
|
|
||||||
throw new AppError("FILE TOO LARGE!");
|
|
||||||
}
|
|
||||||
if (!type) {
|
|
||||||
throw new AppError("FILE TYPE NOT SUPPORTED!");
|
|
||||||
}
|
|
||||||
|
|
||||||
sendWhatsMediaOfficialAPI(ticket, media, type, mic_audio);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// const wbot = await GetTicketWbot(ticket);
|
||||||
|
|
||||||
const newMedia = MessageMedia.fromFilePath(media.path);
|
const newMedia = MessageMedia.fromFilePath(media.path);
|
||||||
|
|
||||||
|
//const sentMessage = await wbot.sendMessage(`${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us`, newMedia, { sendAudioAsVoice: true });
|
||||||
|
|
||||||
sendWhatsAppMediaSocket(ticket, newMedia);
|
sendWhatsAppMediaSocket(ticket, newMedia);
|
||||||
|
|
||||||
await ticket.update({ lastMessage: media.filename });
|
await ticket.update({ lastMessage: media.filename });
|
||||||
|
|
||||||
await updateTicketCacheByTicketId(ticket.id, {
|
// TEST DEL
|
||||||
lastMessage: media.filename,
|
await updateTicketCacheByTicketId(ticket.id, { lastMessage: media.filename, updatedAt: new Date(ticket.updatedAt).toISOString() })
|
||||||
updatedAt: new Date(ticket.updatedAt).toISOString()
|
//
|
||||||
});
|
|
||||||
|
|
||||||
console.log("media.path: ", media.path);
|
console.log('media.path: ', media.path)
|
||||||
fs.unlinkSync(media.path);
|
fs.unlinkSync(media.path);
|
||||||
|
|
||||||
|
// return sentMessage;
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new AppError("ERR_SENDING_WAPP_MSG");
|
throw new AppError("ERR_SENDING_WAPP_MSG");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SendWhatsAppMedia;
|
export default SendWhatsAppMedia;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,19 +8,17 @@ import Ticket from "../../models/Ticket";
|
||||||
import Whatsapp from "../../models/Whatsapp";
|
import Whatsapp from "../../models/Whatsapp";
|
||||||
|
|
||||||
import ShowWhatsAppService from "../WhatsappService/ShowWhatsAppService";
|
import ShowWhatsAppService from "../WhatsappService/ShowWhatsAppService";
|
||||||
import wbotByUserQueue from "../../helpers/GetWbotByUserQueue";
|
import wbotByUserQueue from '../../helpers/GetWbotByUserQueue'
|
||||||
|
|
||||||
import { WhatsIndex } from "../../helpers/LoadBalanceWhatsSameQueue";
|
import { WhatsIndex } from "../../helpers/LoadBalanceWhatsSameQueue";
|
||||||
|
|
||||||
import {
|
import { deleteTicketsByContactsCache, updateTicketCacheByTicketId } from '../../helpers/TicketCache'
|
||||||
deleteTicketsByContactsCache,
|
|
||||||
updateTicketCacheByTicketId
|
|
||||||
} from "../../helpers/TicketCache";
|
|
||||||
|
|
||||||
import ListWhatsAppsNumber from "../WhatsappService/ListWhatsAppsNumber";
|
import ListWhatsAppsNumber from "../WhatsappService/ListWhatsAppsNumber";
|
||||||
import { getWbot } from "../../libs/wbot";
|
import { getWbot } from "../../libs/wbot";
|
||||||
import { json } from "sequelize/types";
|
import { json } from "sequelize/types";
|
||||||
|
|
||||||
|
import sendMessageMultiSession from "../../helpers/TrySendMessageMultiSession";
|
||||||
import { restartWhatsSession } from "../../helpers/RestartWhatsSession";
|
import { restartWhatsSession } from "../../helpers/RestartWhatsSession";
|
||||||
// import { insertOrUpeateWhatsCache, searchWhatsappCache } from "../../helpers/WhatsCache";
|
// import { insertOrUpeateWhatsCache, searchWhatsappCache } from "../../helpers/WhatsCache";
|
||||||
import GetDefaultWhatsApp from "../../helpers/GetDefaultWhatsApp";
|
import GetDefaultWhatsApp from "../../helpers/GetDefaultWhatsApp";
|
||||||
|
@ -28,13 +26,14 @@ import autoRestore from "../../helpers/AutoRestore";
|
||||||
import { _restore } from "../../helpers/RestoreControll";
|
import { _restore } from "../../helpers/RestoreControll";
|
||||||
import { getIO } from "../../libs/socket";
|
import { getIO } from "../../libs/socket";
|
||||||
import sendWhatsAppMessageSocket from "../../helpers/SendWhatsappMessageSocket";
|
import sendWhatsAppMessageSocket from "../../helpers/SendWhatsappMessageSocket";
|
||||||
import sendWhatsAppMessageOfficialAPI from "../../helpers/sendWhatsAppMessageOfficialAPI";
|
|
||||||
|
|
||||||
|
|
||||||
interface Request {
|
interface Request {
|
||||||
body: string;
|
body: string;
|
||||||
ticket: Ticket;
|
ticket: Ticket;
|
||||||
quotedMsg?: Message;
|
quotedMsg?: Message;
|
||||||
number?: string;
|
number?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const SendWhatsAppMessage = async ({
|
const SendWhatsAppMessage = async ({
|
||||||
|
@ -43,111 +42,112 @@ const SendWhatsAppMessage = async ({
|
||||||
quotedMsg,
|
quotedMsg,
|
||||||
number
|
number
|
||||||
}: Request): Promise<WbotMessage | any> => {
|
}: Request): Promise<WbotMessage | any> => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { phoneNumberId } = ticket;
|
|
||||||
|
|
||||||
if (phoneNumberId) {
|
// let timestamp = Math.floor(Date.now() / 1000)
|
||||||
sendWhatsAppMessageOfficialAPI(ticket, body, quotedMsg);
|
let timestamp = Date.now() + String(Math.floor(Math.random() * 1000))
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let timestamp = Date.now() + String(Math.floor(Math.random() * 1000));
|
|
||||||
var timetaken = `########################################${timestamp}| TicketId: ${ticket.id} => Time taken to send the message`;
|
var timetaken = `########################################${timestamp}| TicketId: ${ticket.id} => Time taken to send the message`;
|
||||||
|
|
||||||
console.time(timetaken);
|
console.time(timetaken)
|
||||||
|
|
||||||
|
|
||||||
let quotedMsgSerializedId: string | undefined;
|
let quotedMsgSerializedId: string | undefined;
|
||||||
|
|
||||||
if (quotedMsg) {
|
if (quotedMsg) {
|
||||||
|
|
||||||
await GetWbotMessage(ticket, quotedMsg.id);
|
await GetWbotMessage(ticket, quotedMsg.id);
|
||||||
|
|
||||||
quotedMsgSerializedId = SerializeWbotMsgId(ticket, quotedMsg);
|
quotedMsgSerializedId = SerializeWbotMsgId(ticket, quotedMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("quotedMsgSerializedId: ", quotedMsgSerializedId);
|
console.log('quotedMsgSerializedId: ', quotedMsgSerializedId)
|
||||||
|
|
||||||
let whatsapps: any;
|
|
||||||
|
|
||||||
let listWhatsapp = null;
|
let whatsapps: any
|
||||||
|
|
||||||
|
let listWhatsapp = null
|
||||||
|
|
||||||
// listWhatsapp = await searchWhatsappCache(`${ticket.whatsappId}`, 'CONNECTED')
|
// listWhatsapp = await searchWhatsappCache(`${ticket.whatsappId}`, 'CONNECTED')
|
||||||
|
|
||||||
if (!ticket.whatsappId) {
|
if (!ticket.whatsappId) {
|
||||||
const defaultWhatsapp: any = await GetDefaultWhatsApp({
|
|
||||||
userId: ticket.userId
|
const defaultWhatsapp: any = await GetDefaultWhatsApp(ticket.userId);
|
||||||
});
|
|
||||||
|
|
||||||
await ticket.update({ whatsappId: +defaultWhatsapp.id });
|
await ticket.update({ whatsappId: +defaultWhatsapp.id });
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!listWhatsapp) {
|
if (!listWhatsapp) {
|
||||||
listWhatsapp = await ListWhatsAppsNumber(ticket.whatsappId, "CONNECTED");
|
listWhatsapp = await ListWhatsAppsNumber(ticket.whatsappId, 'CONNECTED')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (listWhatsapp.whatsapp && listWhatsapp.whatsapp.status != 'CONNECTED' && listWhatsapp.whatsapps.length > 0) {
|
||||||
listWhatsapp.whatsapp &&
|
|
||||||
listWhatsapp.whatsapp.status != "CONNECTED" &&
|
await ticket.update({ whatsappId: + listWhatsapp.whatsapps[0].id });
|
||||||
listWhatsapp.whatsapps.length > 0
|
|
||||||
) {
|
|
||||||
await ticket.update({ whatsappId: +listWhatsapp.whatsapps[0].id });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (listWhatsapp.whatsapps.length > 1) {
|
if (listWhatsapp.whatsapps.length > 1) {
|
||||||
const _whatsapp =
|
|
||||||
listWhatsapp.whatsapps[
|
const _whatsapp = listWhatsapp.whatsapps[Math.floor(Math.random() * listWhatsapp.whatsapps.length)];
|
||||||
Math.floor(Math.random() * listWhatsapp.whatsapps.length)
|
|
||||||
];
|
|
||||||
|
|
||||||
await ticket.update({ whatsappId: +_whatsapp.id });
|
await ticket.update({ whatsappId: +_whatsapp.id });
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (listWhatsapp.whatsapps.length == 0 && listWhatsapp.whatsapp.status != 'CONNECTED') {
|
||||||
listWhatsapp.whatsapps.length == 0 &&
|
|
||||||
listWhatsapp.whatsapp.status != "CONNECTED"
|
console.log('listWhatsapp.whatsapps == 0')
|
||||||
) {
|
|
||||||
whatsapps = await wbotByUserQueue({ userId: ticket.userId });
|
whatsapps = await wbotByUserQueue(ticket.userId)
|
||||||
|
|
||||||
|
console.log('============> The whatsapps: ', whatsapps)
|
||||||
|
|
||||||
if (whatsapps.length > 0) {
|
if (whatsapps.length > 0) {
|
||||||
whatsapps = whatsapps.filter((w: any) => !w?.isOfficial);
|
|
||||||
|
|
||||||
if (whatsapps.length > 1) {
|
if (whatsapps.length > 1) {
|
||||||
await ticket.update({
|
|
||||||
whatsappId: whatsapps[+WhatsIndex(whatsapps)].id
|
await ticket.update({ whatsappId: whatsapps[+WhatsIndex(whatsapps)].id });
|
||||||
});
|
|
||||||
} else if (whatsapps && whatsapps.length == 1) {
|
|
||||||
await ticket.update({ whatsappId: whatsapps[0].id });
|
|
||||||
} else {
|
|
||||||
throw new Error(
|
|
||||||
"Sessão de Whatsapp desconectada! Entre em contato com o suporte."
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
await ticket.update({ whatsappId: whatsapps[0].id });
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(
|
console.log('1 --------> send from whatsapp ticket.whatsappId: ', ticket.whatsappId)
|
||||||
"1 --------> send from whatsapp ticket.whatsappId: ",
|
|
||||||
ticket.whatsappId
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
sendWhatsAppMessageSocket(ticket, body, quotedMsgSerializedId, number);
|
sendWhatsAppMessageSocket(ticket, body, quotedMsgSerializedId, number);
|
||||||
|
|
||||||
await ticket.update({ lastMessage: body });
|
await ticket.update({ lastMessage: body });
|
||||||
|
|
||||||
await updateTicketCacheByTicketId(ticket.id, {
|
await updateTicketCacheByTicketId(ticket.id, { lastMessage: body, updatedAt: new Date(ticket.updatedAt).toISOString() })
|
||||||
lastMessage: body,
|
|
||||||
updatedAt: new Date(ticket.updatedAt).toISOString()
|
console.timeEnd(timetaken)
|
||||||
});
|
|
||||||
|
|
||||||
console.timeEnd(timetaken);
|
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
console.error("0 ===> Error on SendWhatsAppMessage.ts file: \n", err);
|
|
||||||
|
console.error('0 ===> Error on SendWhatsAppMessage.ts file: \n', err)
|
||||||
throw new AppError("ERR_SENDING_WAPP_MSG");
|
throw new AppError("ERR_SENDING_WAPP_MSG");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error("===> Error on SendWhatsAppMessage.ts file: \n", error);
|
console.error('===> Error on SendWhatsAppMessage.ts file: \n', error)
|
||||||
throw new AppError(error.message);
|
throw new AppError(error.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SendWhatsAppMessage;
|
export default SendWhatsAppMessage;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -87,10 +87,6 @@ import { Op } from "sequelize";
|
||||||
|
|
||||||
import SettingTicket from "../../models/SettingTicket";
|
import SettingTicket from "../../models/SettingTicket";
|
||||||
import mostRepeatedPhrase from "../../helpers/MostRepeatedPhrase";
|
import mostRepeatedPhrase from "../../helpers/MostRepeatedPhrase";
|
||||||
import ListWhatsAppsNumber from "../WhatsappService/ListWhatsAppsNumber";
|
|
||||||
import { createObject, findObject, get } from "../../helpers/RedisClient";
|
|
||||||
import FindOrCreateTicketServiceBot from "../TicketServices/FindOrCreateTicketServiceBot"
|
|
||||||
import ShowTicketService from "../TicketServices/ShowTicketService"
|
|
||||||
|
|
||||||
var lst: any[] = getWhatsappIds();
|
var lst: any[] = getWhatsappIds();
|
||||||
|
|
||||||
|
@ -100,27 +96,16 @@ interface Session extends Client {
|
||||||
|
|
||||||
const writeFileAsync = promisify(writeFile);
|
const writeFileAsync = promisify(writeFile);
|
||||||
|
|
||||||
const verifyContact = async (
|
const verifyContact = async (msgContact: any): Promise<Contact> => {
|
||||||
msgContact: any,
|
// const profilePicUrl = await msgContact.getProfilePicUrl();
|
||||||
whatsAppOfficial?: any
|
const profilePicUrl = msgContact.getProfilePicUrl;
|
||||||
): Promise<Contact> => {
|
|
||||||
let contactData: any = {};
|
const contactData = {
|
||||||
if (msgContact) {
|
name: msgContact.name || msgContact.pushname || msgContact.id.user,
|
||||||
contactData = {
|
number: msgContact.id.user,
|
||||||
name: msgContact.name || msgContact.pushname || msgContact.id.user,
|
profilePicUrl,
|
||||||
number: msgContact.id.user,
|
isGroup: msgContact.isGroup
|
||||||
profilePicUrl: msgContact.getProfilePicUrl,
|
};
|
||||||
isGroup: msgContact.isGroup
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
contactData = {
|
|
||||||
name: whatsAppOfficial?.name
|
|
||||||
? whatsAppOfficial.name
|
|
||||||
: whatsAppOfficial.number,
|
|
||||||
number: whatsAppOfficial.number,
|
|
||||||
isGroup: false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const contact = CreateOrUpdateContactService(contactData);
|
const contact = CreateOrUpdateContactService(contactData);
|
||||||
|
|
||||||
|
@ -153,11 +138,48 @@ const verifyMediaMessage = async (
|
||||||
media: any,
|
media: any,
|
||||||
quotedMsg?: any
|
quotedMsg?: any
|
||||||
): Promise<Message | any> => {
|
): Promise<Message | any> => {
|
||||||
|
// const quotedMsg = await verifyQuotedMessage(msg);
|
||||||
|
|
||||||
|
// const media = await msg.downloadMedia();
|
||||||
|
|
||||||
if (!media) {
|
if (!media) {
|
||||||
throw new Error("ERR_WAPP_DOWNLOAD_MEDIA");
|
throw new Error("ERR_WAPP_DOWNLOAD_MEDIA");
|
||||||
}
|
}
|
||||||
|
|
||||||
let messageData = {
|
console.log(
|
||||||
|
"MEDIA.FILENAME: ",
|
||||||
|
media.fileName,
|
||||||
|
" | msg.fromMe: ",
|
||||||
|
msg.fromMe
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!media.filename) {
|
||||||
|
console.log("No file name -----------------------------------------");
|
||||||
|
|
||||||
|
const ext = media.mimetype.split("/")[1].split(";")[0];
|
||||||
|
media.filename = `${new Date().getTime()}.${ext}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// await writeFileAsync(
|
||||||
|
// join(__dirname, "..", "..", "..", "public", media.filename),
|
||||||
|
// media.data,
|
||||||
|
// "base64"
|
||||||
|
// );
|
||||||
|
|
||||||
|
console.log("FROM wbotMessageListener.ts media.filename: ", media.filename);
|
||||||
|
|
||||||
|
await writeFileAsync(
|
||||||
|
join(__dirname, "..", "..", "..", "..", "..", "public", media.filename),
|
||||||
|
media.data,
|
||||||
|
"base64"
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
Sentry.captureException(err);
|
||||||
|
logger.error(`There was an error: wbotMessageLitener.ts: ${err}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const messageData = {
|
||||||
id: msg.id.id,
|
id: msg.id.id,
|
||||||
ticketId: ticket.id,
|
ticketId: ticket.id,
|
||||||
contactId: msg.fromMe ? undefined : contact.id,
|
contactId: msg.fromMe ? undefined : contact.id,
|
||||||
|
@ -166,112 +188,26 @@ const verifyMediaMessage = async (
|
||||||
read: msg.fromMe,
|
read: msg.fromMe,
|
||||||
mediaUrl: media.filename,
|
mediaUrl: media.filename,
|
||||||
mediaType: media.mimetype.split("/")[0],
|
mediaType: media.mimetype.split("/")[0],
|
||||||
quotedMsgId: quotedMsg,
|
quotedMsgId: quotedMsg
|
||||||
phoneNumberId: msg?.phoneNumberId
|
// quotedMsgId: quotedMsg?.id
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!ticket?.phoneNumberId) {
|
|
||||||
if (!media.filename) {
|
|
||||||
const ext = media.mimetype.split("/")[1].split(";")[0];
|
|
||||||
media.filename = `${new Date().getTime()}.${ext}`;
|
|
||||||
messageData = {
|
|
||||||
...messageData,
|
|
||||||
mediaUrl: media.filename,
|
|
||||||
body: media.filename
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await writeFileAsync(
|
|
||||||
join(__dirname, "..", "..", "..", "..", "..", "public", media.filename),
|
|
||||||
media.data,
|
|
||||||
"base64"
|
|
||||||
);
|
|
||||||
} catch (err) {
|
|
||||||
Sentry.captureException(err);
|
|
||||||
logger.error(`There was an error: wbotMessageLitener.ts: ${err}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await ticket.update({ lastMessage: msg.body || media.filename });
|
await ticket.update({ lastMessage: msg.body || media.filename });
|
||||||
const newMessage = await CreateMessageService({ messageData });
|
const newMessage = await CreateMessageService({ messageData });
|
||||||
|
|
||||||
return newMessage;
|
return newMessage;
|
||||||
};
|
};
|
||||||
|
|
||||||
// const verifyMediaMessage = async (
|
|
||||||
// msg: any,
|
|
||||||
// ticket: Ticket,
|
|
||||||
// contact: Contact,
|
|
||||||
// media: any,
|
|
||||||
// quotedMsg?: any
|
|
||||||
// ): Promise<Message | any> => {
|
|
||||||
// // const quotedMsg = await verifyQuotedMessage(msg);
|
|
||||||
|
|
||||||
// // const media = await msg.downloadMedia();
|
|
||||||
|
|
||||||
// if (!media) {
|
|
||||||
// throw new Error("ERR_WAPP_DOWNLOAD_MEDIA");
|
|
||||||
// }
|
|
||||||
|
|
||||||
// console.log(
|
|
||||||
// "MEDIA.FILENAME: ",
|
|
||||||
// media.fileName,
|
|
||||||
// " | msg.fromMe: ",
|
|
||||||
// msg.fromMe
|
|
||||||
// );
|
|
||||||
|
|
||||||
// if (!media.filename) {
|
|
||||||
// console.log("No file name -----------------------------------------");
|
|
||||||
|
|
||||||
// const ext = media.mimetype.split("/")[1].split(";")[0];
|
|
||||||
// media.filename = `${new Date().getTime()}.${ext}`;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// try {
|
|
||||||
// // await writeFileAsync(
|
|
||||||
// // join(__dirname, "..", "..", "..", "public", media.filename),
|
|
||||||
// // media.data,
|
|
||||||
// // "base64"
|
|
||||||
// // );
|
|
||||||
|
|
||||||
// console.log("FROM wbotMessageListener.ts media.filename: ", media.filename);
|
|
||||||
|
|
||||||
// await writeFileAsync(
|
|
||||||
// join(__dirname, "..", "..", "..", "..", "..", "public", media.filename),
|
|
||||||
// media.data,
|
|
||||||
// "base64"
|
|
||||||
// );
|
|
||||||
// } catch (err) {
|
|
||||||
// Sentry.captureException(err);
|
|
||||||
// logger.error(`There was an error: wbotMessageLitener.ts: ${err}`);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const messageData = {
|
|
||||||
// id: msg.id.id,
|
|
||||||
// ticketId: ticket.id,
|
|
||||||
// contactId: msg.fromMe ? undefined : contact.id,
|
|
||||||
// body: msg.body || media.filename,
|
|
||||||
// fromMe: msg.fromMe,
|
|
||||||
// read: msg.fromMe,
|
|
||||||
// mediaUrl: media.filename,
|
|
||||||
// mediaType: media.mimetype.split("/")[0],
|
|
||||||
// quotedMsgId: quotedMsg
|
|
||||||
// // quotedMsgId: quotedMsg?.id
|
|
||||||
// };
|
|
||||||
|
|
||||||
// await ticket.update({ lastMessage: msg.body || media.filename });
|
|
||||||
// const newMessage = await CreateMessageService({ messageData });
|
|
||||||
|
|
||||||
// return newMessage;
|
|
||||||
// };
|
|
||||||
|
|
||||||
const verifyMessage = async (
|
const verifyMessage = async (
|
||||||
msg: any,
|
msg: WbotMessage,
|
||||||
ticket: Ticket,
|
ticket: Ticket,
|
||||||
contact: Contact,
|
contact: Contact,
|
||||||
quotedMsg?: any
|
quotedMsg?: any
|
||||||
) => {
|
) => {
|
||||||
|
// const quotedMsg = await verifyQuotedMessage(msg);
|
||||||
|
|
||||||
|
// const quotedMsg = await verifyQuotedMessage(msg);
|
||||||
|
|
||||||
const messageData = {
|
const messageData = {
|
||||||
id: msg.id.id,
|
id: msg.id.id,
|
||||||
ticketId: ticket.id,
|
ticketId: ticket.id,
|
||||||
|
@ -280,8 +216,8 @@ const verifyMessage = async (
|
||||||
fromMe: msg.fromMe,
|
fromMe: msg.fromMe,
|
||||||
mediaType: msg.type,
|
mediaType: msg.type,
|
||||||
read: msg.fromMe,
|
read: msg.fromMe,
|
||||||
quotedMsgId: quotedMsg,
|
quotedMsgId: quotedMsg
|
||||||
phoneNumberId: msg?.phoneNumberId
|
// quotedMsgId: quotedMsg?.id
|
||||||
};
|
};
|
||||||
|
|
||||||
await ticket.update({ lastMessage: msg.body });
|
await ticket.update({ lastMessage: msg.body });
|
||||||
|
@ -297,12 +233,20 @@ const verifyQueue = async (
|
||||||
) => {
|
) => {
|
||||||
const { queues, greetingMessage } = await ShowWhatsAppService(wbot.id!);
|
const { queues, greetingMessage } = await ShowWhatsAppService(wbot.id!);
|
||||||
|
|
||||||
|
/*if (queues.length === 1) {
|
||||||
|
await UpdateTicketService({
|
||||||
|
ticketData: { queueId: queues[0].id },
|
||||||
|
ticketId: ticket.id
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}*/
|
||||||
|
|
||||||
let selectedOption = null;
|
let selectedOption = null;
|
||||||
let choosenQueue = null;
|
let choosenQueue = null;
|
||||||
|
|
||||||
//Habilitar esse caso queira usar o bot
|
//Habilitar esse caso queira usar o bot
|
||||||
const botInfo = await BotIsOnQueue("botqueue");
|
// const botInfo = await BotIsOnQueue('botqueue')
|
||||||
// const botInfo = { isOnQueue: false, botQueueId: 0, userIdBot: 0 };
|
const botInfo = { isOnQueue: false, botQueueId: 0, userIdBot: 0 };
|
||||||
|
|
||||||
if (botInfo.isOnQueue) {
|
if (botInfo.isOnQueue) {
|
||||||
choosenQueue = await ShowQueueService(botInfo.botQueueId);
|
choosenQueue = await ShowQueueService(botInfo.botQueueId);
|
||||||
|
@ -340,23 +284,13 @@ const verifyQueue = async (
|
||||||
ticketId: ticket.id
|
ticketId: ticket.id
|
||||||
});
|
});
|
||||||
|
|
||||||
const data = await get("ura");
|
data_ura.forEach((s, index) => {
|
||||||
|
botOptions += `*${index + 1}* - ${s.option}\n`;
|
||||||
await createObject({
|
|
||||||
whatsappId: `${ticket.whatsappId}`,
|
|
||||||
contactId: `${ticket.contactId}`,
|
|
||||||
identifier: "ura",
|
|
||||||
value: data[1].id
|
|
||||||
});
|
});
|
||||||
|
|
||||||
botSendMessage(ticket, data[1].value);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
|
|
||||||
let whatsapp: any = await whatsappInfo(ticket?.whatsappId);
|
const outService = await outOfService();
|
||||||
|
|
||||||
const outService = await outOfService(whatsapp?.number);
|
|
||||||
|
|
||||||
if (outService.length > 0) {
|
if (outService.length > 0) {
|
||||||
const { type, msg: msgOutService } = outService[0];
|
const { type, msg: msgOutService } = outService[0];
|
||||||
|
@ -373,6 +307,9 @@ const verifyQueue = async (
|
||||||
body = `\u200e${choosenQueue.greetingMessage}`;
|
body = `\u200e${choosenQueue.greetingMessage}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// const sentMessage = await wbot.sendMessage(`${contact.number}@c.us`, body);
|
||||||
|
// await verifyMessage(sentMessage, ticket, contact);
|
||||||
|
|
||||||
sendWhatsAppMessageSocket(ticket, body);
|
sendWhatsAppMessageSocket(ticket, body);
|
||||||
} else {
|
} else {
|
||||||
//test del transfere o atendimento se entrar na ura infinita
|
//test del transfere o atendimento se entrar na ura infinita
|
||||||
|
@ -399,13 +336,14 @@ const verifyQueue = async (
|
||||||
|
|
||||||
const body = `\u200e${greetingMessage}\n${options}`;
|
const body = `\u200e${greetingMessage}\n${options}`;
|
||||||
|
|
||||||
const { phoneNumberId } = ticket;
|
|
||||||
|
|
||||||
const debouncedSentMessage = debounce(
|
const debouncedSentMessage = debounce(
|
||||||
async () => {
|
async () => {
|
||||||
|
// const sentMessage = await wbot.sendMessage(`${contact.number}@c.us`, body);
|
||||||
|
// verifyMessage(sentMessage, ticket, contact);
|
||||||
|
|
||||||
sendWhatsAppMessageSocket(ticket, body);
|
sendWhatsAppMessageSocket(ticket, body);
|
||||||
},
|
},
|
||||||
phoneNumberId ? 0 : 3000,
|
3000,
|
||||||
ticket.id
|
ticket.id
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -414,57 +352,9 @@ const verifyQueue = async (
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const mediaTypeWhatsappOfficial = (mimetype: string): object => {
|
const isValidMsg = (msg: WbotMessage): boolean => {
|
||||||
const document = [
|
|
||||||
"text/plain",
|
|
||||||
"text/csv",
|
|
||||||
"application/pdf",
|
|
||||||
"application/vnd.ms-powerpoint",
|
|
||||||
"application/msword",
|
|
||||||
"application/vnd.ms-excel",
|
|
||||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
||||||
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
||||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
||||||
];
|
|
||||||
|
|
||||||
const image = ["image/jpeg", "image/png"];
|
|
||||||
|
|
||||||
const video = ["video/mp4", "video/3gp"];
|
|
||||||
|
|
||||||
const sticker = ["image/webp"];
|
|
||||||
|
|
||||||
const audio = [
|
|
||||||
"audio/mp3",
|
|
||||||
"audio/aac",
|
|
||||||
"audio/mp4",
|
|
||||||
"audio/mpeg",
|
|
||||||
"audio/amr",
|
|
||||||
"audio/ogg"
|
|
||||||
];
|
|
||||||
|
|
||||||
const types = [
|
|
||||||
{ name: "document", values: document, mbMaxSize: 15 },
|
|
||||||
{ name: "image", values: image, mbMaxSize: 5 },
|
|
||||||
{ name: "video", values: video, mbMaxSize: 15 },
|
|
||||||
{ name: "sticker", values: sticker, mbMaxSize: 0.5 },
|
|
||||||
{ name: "audio", values: audio, mbMaxSize: 15 }
|
|
||||||
];
|
|
||||||
|
|
||||||
for (let i in types) {
|
|
||||||
if (types[i].values.includes(mimetype)) {
|
|
||||||
return { type: types[i].name, mbMaxSize: types[i].mbMaxSize };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { type: null, mbsize: 0 };
|
|
||||||
};
|
|
||||||
|
|
||||||
const isValidMsg = (msg: any): boolean => {
|
|
||||||
if (msg.from === "status@broadcast") return false;
|
if (msg.from === "status@broadcast") return false;
|
||||||
if (
|
if (
|
||||||
msg.type === "template" ||
|
|
||||||
msg.type === "text" ||
|
|
||||||
msg.type === "hsm" ||
|
|
||||||
msg.type === "chat" ||
|
msg.type === "chat" ||
|
||||||
msg.type === "audio" ||
|
msg.type === "audio" ||
|
||||||
msg.type === "ptt" ||
|
msg.type === "ptt" ||
|
||||||
|
@ -490,35 +380,12 @@ const queuesOutBot = async (wbot: Session, botId: string | number) => {
|
||||||
return { queues, greetingMessage };
|
return { queues, greetingMessage };
|
||||||
};
|
};
|
||||||
|
|
||||||
const transferTicket = async (queueName: any, wbot: any, ticket: Ticket) => {
|
const botTransferTicket = async (
|
||||||
const botInfo = await BotIsOnQueue("botqueue");
|
queues: Queue,
|
||||||
|
ticket: Ticket,
|
||||||
console.log("kkkkkkkkkkkkkkkkkkkkk queueName: ", queueName);
|
contact: Contact,
|
||||||
|
wbot: Session
|
||||||
const queuesWhatsGreetingMessage = await queuesOutBot(
|
) => {
|
||||||
wbot,
|
|
||||||
botInfo.botQueueId
|
|
||||||
);
|
|
||||||
|
|
||||||
let queue: any;
|
|
||||||
|
|
||||||
const queues = queuesWhatsGreetingMessage.queues;
|
|
||||||
|
|
||||||
// console.log("queues ---> ", console.log(JSON.stringify(queues, null, 6)));
|
|
||||||
|
|
||||||
if (typeof queueName == "string") {
|
|
||||||
queue = queues.find(
|
|
||||||
(q: any) => q?.name?.toLowerCase() == queueName.trim().toLowerCase()
|
|
||||||
);
|
|
||||||
// await deleteObject(wbot.id, `${ticket.contactId}`, "ura");
|
|
||||||
} else if (typeof queueName == "number") {
|
|
||||||
queue = queues[queueName];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (queue) await botTransferTicket(queue, ticket);
|
|
||||||
};
|
|
||||||
|
|
||||||
const botTransferTicket = async (queues: Queue, ticket: Ticket) => {
|
|
||||||
await ticket.update({ userId: null });
|
await ticket.update({ userId: null });
|
||||||
|
|
||||||
await UpdateTicketService({
|
await UpdateTicketService({
|
||||||
|
@ -528,19 +395,43 @@ const botTransferTicket = async (queues: Queue, ticket: Ticket) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const botSendMessage = (ticket: Ticket, msg: string) => {
|
const botSendMessage = (ticket: Ticket, msg: string) => {
|
||||||
const { phoneNumberId } = ticket;
|
|
||||||
|
|
||||||
const debouncedSentMessage = debounce(
|
const debouncedSentMessage = debounce(
|
||||||
async () => {
|
async () => {
|
||||||
|
//OLD
|
||||||
|
// const sentMessage = await wbot.sendMessage(`${contact.number}@c.us`, `${msg}`);
|
||||||
|
// verifyMessage(sentMessage, ticket, contact);
|
||||||
|
|
||||||
|
//NEW
|
||||||
await SendWhatsAppMessage({ body: msg, ticket });
|
await SendWhatsAppMessage({ body: msg, ticket });
|
||||||
},
|
},
|
||||||
phoneNumberId ? 0 : 3000,
|
3000,
|
||||||
ticket.id
|
ticket.id
|
||||||
);
|
);
|
||||||
|
|
||||||
debouncedSentMessage();
|
debouncedSentMessage();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// const botSendMessage = (
|
||||||
|
// ticket: Ticket,
|
||||||
|
// contact: Contact,
|
||||||
|
// wbot: Session,
|
||||||
|
// msg: string
|
||||||
|
// ) => {
|
||||||
|
// const debouncedSentMessage = debounce(
|
||||||
|
// async () => {
|
||||||
|
// const sentMessage = await wbot.sendMessage(
|
||||||
|
// `${contact.number}@c.us`,
|
||||||
|
// `${msg}`
|
||||||
|
// );
|
||||||
|
// verifyMessage(sentMessage, ticket, contact);
|
||||||
|
// },
|
||||||
|
// 3000,
|
||||||
|
// ticket.id
|
||||||
|
// );
|
||||||
|
|
||||||
|
// debouncedSentMessage();
|
||||||
|
// };
|
||||||
|
|
||||||
const _clear_lst = () => {
|
const _clear_lst = () => {
|
||||||
console.log("THE lst.length: ", lst.length);
|
console.log("THE lst.length: ", lst.length);
|
||||||
|
|
||||||
|
@ -555,29 +446,30 @@ const _clear_lst = () => {
|
||||||
setWhatsappId(whatsappIdsSplited, true);
|
setWhatsappId(whatsappIdsSplited, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMessage = async (
|
const handleMessage = async (msg: any, wbot: any): Promise<void> => {
|
||||||
msg: any,
|
// if (!msg.fromMe) {
|
||||||
wbot: any,
|
_clear_lst();
|
||||||
whatsAppOfficial?: any
|
|
||||||
): Promise<void> => {
|
|
||||||
if (!whatsAppOfficial) {
|
|
||||||
_clear_lst();
|
|
||||||
|
|
||||||
let index = lst.findIndex((x: any) => x.id == msg.id.id);
|
let index = lst.findIndex((x: any) => x.id == msg.id.id);
|
||||||
|
|
||||||
console.log("INDEX: ", index);
|
console.log("INDEX: ", index);
|
||||||
|
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
lst.push({ id: msg.id.id });
|
// console.log('-----------------> LST: ', lst):q
|
||||||
|
|
||||||
setWhatsappId(msg.id.id);
|
lst.push({ id: msg.id.id });
|
||||||
} else {
|
|
||||||
console.log("IGNORED ID: ", msg.id.id);
|
|
||||||
|
|
||||||
return;
|
setWhatsappId(msg.id.id);
|
||||||
}
|
} else {
|
||||||
|
console.log("IGNORED ID: ", msg.id.id);
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// console.log('LIST OF ID MESSAGE lst: ', lst)
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
if (!isValidMsg(msg)) {
|
if (!isValidMsg(msg)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -587,32 +479,44 @@ const handleMessage = async (
|
||||||
// let groupContact: Contact | undefined;
|
// let groupContact: Contact | undefined;
|
||||||
|
|
||||||
if (msg.fromMe) {
|
if (msg.fromMe) {
|
||||||
const whatsapp = await whatsappInfo(wbot.id);
|
const ticketExpiration = await SettingTicket.findOne({
|
||||||
|
where: { key: "ticketExpiration" }
|
||||||
|
});
|
||||||
|
|
||||||
if (whatsapp?.number) {
|
if (
|
||||||
const ticketExpiration = await SettingTicket.findOne({
|
ticketExpiration &&
|
||||||
where: { key: "ticketExpiration", number: whatsapp.number }
|
ticketExpiration.value == "enabled" &&
|
||||||
});
|
ticketExpiration?.message.trim() == msg.body.trim()
|
||||||
|
) {
|
||||||
if (
|
console.log("*********** TICKET EXPIRATION");
|
||||||
ticketExpiration &&
|
return;
|
||||||
ticketExpiration.value == "enabled" &&
|
|
||||||
ticketExpiration?.message.trim() == msg.body.trim()
|
|
||||||
) {
|
|
||||||
console.log("*********** TICKET EXPIRATION");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// console.log('FROM ME: ', msg.fromMe, ' | /\u200e/.test(msg.body[0]: ', (/\u200e/.test(msg.body[0])))
|
||||||
|
|
||||||
// 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
|
||||||
// if so, this message was already been stored in database;
|
// if so, this message was already been stored in database;
|
||||||
// if (/\u200e/.test(msg.body[0])) return;
|
// if (/\u200e/.test(msg.body[0])) return;
|
||||||
|
|
||||||
|
// console.log('PASSOU 1')
|
||||||
|
|
||||||
// media messages sent from me from cell phone, first comes with "hasMedia = false" and type = "image/ptt/etc"
|
// media messages sent from me from cell phone, first comes with "hasMedia = false" and type = "image/ptt/etc"
|
||||||
// in this case, return and let this message be handled by "media_uploaded" event, when it will have "hasMedia = true"
|
// in this case, return and let this message be handled by "media_uploaded" event, when it will have "hasMedia = true"
|
||||||
|
|
||||||
if (!msg.hasMedia && msg.type !== "chat" && msg.type !== "vcard") return;
|
if (!msg.hasMedia && msg.type !== "chat" && msg.type !== "vcard") return;
|
||||||
|
|
||||||
|
// console.log('PASSOU 2')
|
||||||
|
|
||||||
|
// msgContact = await wbot.getContactById(msg.to);
|
||||||
|
|
||||||
|
// console.log('1 --------------> msgContat: ', JSON.parse(JSON.stringify(msgContact)))
|
||||||
|
// console.log(' # msg.type: ', msg.type )
|
||||||
} else {
|
} else {
|
||||||
|
// msgContact = await msg.getContact();
|
||||||
|
|
||||||
|
// console.log('2 --------------> msgContat: ', JSON.parse(JSON.stringify(msgContact)))
|
||||||
|
|
||||||
|
//
|
||||||
console.log(`\n <<<<<<<<<< RECEIVING MESSAGE:
|
console.log(`\n <<<<<<<<<< RECEIVING MESSAGE:
|
||||||
Parcial msg and msgContact info:
|
Parcial msg and msgContact info:
|
||||||
msgContact.name: ${msgContact.name}
|
msgContact.name: ${msgContact.name}
|
||||||
|
@ -625,6 +529,7 @@ const handleMessage = async (
|
||||||
msg.from: ${msg.from}
|
msg.from: ${msg.from}
|
||||||
msg.to: ${msg.to}\n`);
|
msg.to: ${msg.to}\n`);
|
||||||
}
|
}
|
||||||
|
// const chat = await msg.getChat();
|
||||||
const chat = wbot.chat;
|
const chat = wbot.chat;
|
||||||
|
|
||||||
// if(chat.isGroup){
|
// if(chat.isGroup){
|
||||||
|
@ -649,14 +554,13 @@ const handleMessage = async (
|
||||||
|
|
||||||
const whatsapp = await ShowWhatsAppService(wbot.id!);
|
const whatsapp = await ShowWhatsAppService(wbot.id!);
|
||||||
|
|
||||||
|
// const whatsapp = await ShowWhatsAppService(46);
|
||||||
|
|
||||||
const unreadMessages = msg.fromMe ? 0 : chat.unreadCount;
|
const unreadMessages = msg.fromMe ? 0 : chat.unreadCount;
|
||||||
|
|
||||||
const contact = !whatsAppOfficial
|
const contact = await verifyContact(msgContact);
|
||||||
? await verifyContact(msgContact)
|
|
||||||
: await verifyContact(null, {
|
// console.log('----------> contact: ', JSON.parse(JSON.stringify(contact)))
|
||||||
number: wbot.msgContact.number,
|
|
||||||
name: wbot.msgContact.name
|
|
||||||
});
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
unreadMessages === 0 &&
|
unreadMessages === 0 &&
|
||||||
|
@ -665,39 +569,15 @@ const handleMessage = async (
|
||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let ticket;
|
const ticket = await FindOrCreateTicketService(
|
||||||
|
contact,
|
||||||
const _botInfo = await BotIsOnQueue("botqueue");
|
wbot.id!,
|
||||||
|
unreadMessages
|
||||||
if (_botInfo.isOnQueue) {
|
// groupContact
|
||||||
let ticket_obj: any = await FindOrCreateTicketServiceBot(
|
);
|
||||||
contact,
|
|
||||||
wbot.id!,
|
|
||||||
unreadMessages
|
|
||||||
// groupContact
|
|
||||||
);
|
|
||||||
|
|
||||||
ticket = ticket_obj.ticket;
|
|
||||||
|
|
||||||
if (ticket_obj.created) {
|
|
||||||
let queue = await ShowQueueService(_botInfo.botQueueId);
|
|
||||||
|
|
||||||
await UpdateTicketService({
|
|
||||||
ticketData: { queueId: queue.id },
|
|
||||||
ticketId: ticket.id
|
|
||||||
});
|
|
||||||
|
|
||||||
ticket = await ShowTicketService(ticket.id);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ticket = await FindOrCreateTicketService(
|
|
||||||
contact,
|
|
||||||
wbot.id!,
|
|
||||||
unreadMessages
|
|
||||||
// groupContact
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// await updateTicketCacheByTicketId(ticket.id, {'contact.profilePicUrl': ticket.contact.profilePicUrl})
|
||||||
|
|
||||||
if (getSettingValue("oneContactChatWithManyWhats")?.value == "disabled") {
|
if (getSettingValue("oneContactChatWithManyWhats")?.value == "disabled") {
|
||||||
// Para responder para o cliente pelo mesmo whatsapp que ele enviou a mensagen
|
// Para responder para o cliente pelo mesmo whatsapp que ele enviou a mensagen
|
||||||
|
@ -744,88 +624,9 @@ const handleMessage = async (
|
||||||
// O bot interage com o cliente e encaminha o atendimento para fila de atendende quando o usuário escolhe a opção falar com atendente
|
// O bot interage com o cliente e encaminha o atendimento para fila de atendende quando o usuário escolhe a opção falar com atendente
|
||||||
|
|
||||||
//Habilitar esse caso queira usar o bot
|
//Habilitar esse caso queira usar o bot
|
||||||
const botInfo = await BotIsOnQueue("botqueue");
|
// const botInfo = await BotIsOnQueue('botqueue')
|
||||||
// const botInfo = { isOnQueue: false, botQueueId: 0, userIdBot: 0 };
|
// const botInfo = { isOnQueue: false, botQueueId: 0, userIdBot: 0 };
|
||||||
|
|
||||||
if (
|
|
||||||
botInfo.isOnQueue &&
|
|
||||||
!msg.fromMe &&
|
|
||||||
ticket.userId == botInfo.userIdBot
|
|
||||||
) {
|
|
||||||
const repet: any = await mostRepeatedPhrase(ticket.id);
|
|
||||||
|
|
||||||
console.log("repet.occurrences: ", repet.occurrences);
|
|
||||||
|
|
||||||
if (repet.occurrences > 4) {
|
|
||||||
await transferTicket(0, wbot, ticket);
|
|
||||||
|
|
||||||
await SendWhatsAppMessage({
|
|
||||||
body: `Seu atendimento foi transferido para um agente!\n\nPara voltar ao menu principal digite *0*
|
|
||||||
`,
|
|
||||||
ticket,
|
|
||||||
number: `${contact.number}@c.us`
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
console.log("MSG body: ", msg.body);
|
|
||||||
|
|
||||||
if (msg.type != "chat") {
|
|
||||||
botSendMessage(
|
|
||||||
ticket,
|
|
||||||
`Desculpe, nao compreendi!\nEnvie apenas texto quando estiver interagindo com o bot!\n _Digite *0* para voltar ao menu principal._`
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg.type == "chat" && String(msg.body).length > 120) {
|
|
||||||
botSendMessage(
|
|
||||||
ticket,
|
|
||||||
`Desculpe, nao compreendi!\nTexto acima de 120 caracteres!\n _Digite *0* para voltar ao menu principal._`
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const menuMsg: any = await menu(msg.body, wbot.id, contact.id);
|
|
||||||
|
|
||||||
console.log("menuMsg: ", menuMsg);
|
|
||||||
|
|
||||||
await botSendMessage(ticket, menuMsg.value);
|
|
||||||
|
|
||||||
if (
|
|
||||||
menuMsg?.transferToQueue &&
|
|
||||||
menuMsg.transferToQueue.trim().length > 0
|
|
||||||
) {
|
|
||||||
console.log(
|
|
||||||
"YYYYYYYYYYYYYYYYYYYY menuMsg.transferToQueue: ",
|
|
||||||
menuMsg.transferToQueue
|
|
||||||
);
|
|
||||||
|
|
||||||
transferTicket(menuMsg.transferToQueue.trim(), wbot, ticket);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
} else if (
|
|
||||||
!msg.fromMe &&
|
|
||||||
msg.body == "0" &&
|
|
||||||
ticket.status == "pending" &&
|
|
||||||
ticket.queueId
|
|
||||||
) {
|
|
||||||
let choosenQueue = await ShowQueueService(botInfo.botQueueId);
|
|
||||||
|
|
||||||
await UpdateTicketService({
|
|
||||||
ticketData: {
|
|
||||||
status: "open",
|
|
||||||
userId: botInfo.userIdBot,
|
|
||||||
queueId: choosenQueue.id
|
|
||||||
},
|
|
||||||
ticketId: ticket.id
|
|
||||||
});
|
|
||||||
const menuMsg: any = await menu(msg.body, wbot.id, contact.id);
|
|
||||||
await botSendMessage(ticket, menuMsg.value);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg && !msg.fromMe && ticket.status == "pending") {
|
if (msg && !msg.fromMe && ticket.status == "pending") {
|
||||||
await setMessageAsRead(ticket);
|
await setMessageAsRead(ticket);
|
||||||
}
|
}
|
||||||
|
@ -837,9 +638,7 @@ const handleMessage = async (
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ticketHasQueue && ticket.status != "open") {
|
if (ticketHasQueue && ticket.status != "open") {
|
||||||
let whatsapp: any = await whatsappInfo(ticket?.whatsappId);
|
const outService = await outOfService();
|
||||||
|
|
||||||
const outService = await outOfService(whatsapp.number);
|
|
||||||
|
|
||||||
if (outService.length > 0) {
|
if (outService.length > 0) {
|
||||||
const { type, msg: msgOutService } = outService[0];
|
const { type, msg: msgOutService } = outService[0];
|
||||||
|
@ -860,143 +659,8 @@ const handleMessage = async (
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const menu = async (userTyped: string, whatsappId: any, contactId: any) => {
|
const handleMsgAck = async (msg_id: any, ack: any) => {
|
||||||
let lastId = await findObject(whatsappId, contactId, "ura");
|
await new Promise(r => setTimeout(r, 4000));
|
||||||
const data: any = await get("ura");
|
|
||||||
|
|
||||||
console.log("lastId[0]: ", lastId[0]);
|
|
||||||
|
|
||||||
if (!lastId[0]) {
|
|
||||||
await createObject({
|
|
||||||
whatsappId,
|
|
||||||
contactId,
|
|
||||||
identifier: "ura",
|
|
||||||
value: data[1].id
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
lastId = await findObject(whatsappId, contactId, "ura");
|
|
||||||
console.log("LAST ID: ", lastId);
|
|
||||||
let option: any;
|
|
||||||
|
|
||||||
if (
|
|
||||||
lastId &&
|
|
||||||
lastId.length == 4 &&
|
|
||||||
lastId[3] &&
|
|
||||||
lastId[3].trim().length > 0
|
|
||||||
) {
|
|
||||||
option = data.find(
|
|
||||||
(o: any) =>
|
|
||||||
o.idmaster == lastId[3] &&
|
|
||||||
o.value.toLowerCase() == userTyped.toLowerCase()
|
|
||||||
);
|
|
||||||
|
|
||||||
// TEST DEL
|
|
||||||
console.log("OPTION: ", option);
|
|
||||||
|
|
||||||
if (!option && userTyped != "0") {
|
|
||||||
if (!existSubMenu()) {
|
|
||||||
const response = await mainOptionsMenu(userTyped);
|
|
||||||
if (response) return response;
|
|
||||||
else {
|
|
||||||
console.log("kkkkkkkkkkkkkkkkkkk");
|
|
||||||
await createObject({
|
|
||||||
whatsappId,
|
|
||||||
contactId,
|
|
||||||
identifier: "ura",
|
|
||||||
value: data[1].id
|
|
||||||
});
|
|
||||||
|
|
||||||
return data[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//
|
|
||||||
|
|
||||||
if (option) {
|
|
||||||
let response: any = data.find((o: any) => o.idmaster == option.id);
|
|
||||||
|
|
||||||
console.log(
|
|
||||||
"RRRRRRRRRRRRRRRRRRRRRRRRRRRRR response: ",
|
|
||||||
response,
|
|
||||||
" | option: ",
|
|
||||||
option
|
|
||||||
);
|
|
||||||
|
|
||||||
await createObject({
|
|
||||||
whatsappId,
|
|
||||||
contactId,
|
|
||||||
identifier: "ura",
|
|
||||||
value: response.id
|
|
||||||
});
|
|
||||||
|
|
||||||
return response;
|
|
||||||
} else if (userTyped == "0") {
|
|
||||||
await createObject({
|
|
||||||
whatsappId,
|
|
||||||
contactId,
|
|
||||||
identifier: "ura",
|
|
||||||
value: data[1].id
|
|
||||||
});
|
|
||||||
|
|
||||||
return data[1];
|
|
||||||
} else {
|
|
||||||
console.log("INVALID SEARCH");
|
|
||||||
|
|
||||||
let response = await existSubMenu();
|
|
||||||
if (response) return response;
|
|
||||||
|
|
||||||
return {
|
|
||||||
value: data.find((o: any) => o.id == lastId[3])?.value
|
|
||||||
};
|
|
||||||
|
|
||||||
// return {
|
|
||||||
// value: `Você digitou uma opçao inválida!\n\n${
|
|
||||||
// data.find((o: any) => o.id == lastId[3])?.value
|
|
||||||
// }\n\nDigite 0 para voltar ao menu `
|
|
||||||
// };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function existSubMenu() {
|
|
||||||
let existSubMenu = data.find((o: any) => o.idmaster == lastId[3]);
|
|
||||||
|
|
||||||
if (existSubMenu) true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function mainOptionsMenu(userTyped: any) {
|
|
||||||
let menuOption = data.find(
|
|
||||||
(o: any) => o.value.toLowerCase() == userTyped.toLowerCase()
|
|
||||||
);
|
|
||||||
console.log("============> menuOption OPTION: ", menuOption);
|
|
||||||
if (menuOption) {
|
|
||||||
let response = data.find((o: any) => o.idmaster == menuOption.id);
|
|
||||||
if (response) {
|
|
||||||
await createObject({
|
|
||||||
whatsappId,
|
|
||||||
contactId,
|
|
||||||
identifier: "ura",
|
|
||||||
value: response.id
|
|
||||||
});
|
|
||||||
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMsgAck = async (
|
|
||||||
msg_id: any,
|
|
||||||
ack: any,
|
|
||||||
whatsAppOfficial?: boolean
|
|
||||||
) => {
|
|
||||||
if (whatsAppOfficial) {
|
|
||||||
if (ack == "sent") ack = 1;
|
|
||||||
else if (ack == "delivered") ack = 2;
|
|
||||||
else if (ack == "read") ack = 3;
|
|
||||||
} else await new Promise(r => setTimeout(r, 4000));
|
|
||||||
|
|
||||||
const io = getIO();
|
const io = getIO();
|
||||||
|
|
||||||
|
@ -1017,11 +681,6 @@ const handleMsgAck = async (
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("messageToUpdate.ack: ", messageToUpdate.ack, " | ack: ", ack);
|
|
||||||
|
|
||||||
if (messageToUpdate.ack > ack) return;
|
|
||||||
|
|
||||||
await messageToUpdate.update({ ack });
|
await messageToUpdate.update({ ack });
|
||||||
|
|
||||||
io.to(messageToUpdate.ticketId.toString()).emit("appMessage", {
|
io.to(messageToUpdate.ticketId.toString()).emit("appMessage", {
|
||||||
|
@ -1048,9 +707,9 @@ const wbotMessageListener = (wbot: Session): void => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const outOfService = async (number: string) => {
|
const outOfService = async () => {
|
||||||
// MESSAGE TO HOLIDAY
|
// MESSAGE TO HOLIDAY
|
||||||
const holiday: any = await isHoliday(number);
|
const holiday: any = await isHoliday();
|
||||||
|
|
||||||
let objs: any = [];
|
let objs: any = [];
|
||||||
|
|
||||||
|
@ -1059,14 +718,14 @@ const outOfService = async (number: string) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MESSAGES TO SATURDAY OR SUNDAY
|
// MESSAGES TO SATURDAY OR SUNDAY
|
||||||
const weekend: any = await isWeekend(number);
|
const weekend: any = await isWeekend();
|
||||||
|
|
||||||
if (weekend && weekend.set) {
|
if (weekend && weekend.set) {
|
||||||
objs.push({ type: "weekend", msg: weekend.msg });
|
objs.push({ type: "weekend", msg: weekend.msg });
|
||||||
}
|
}
|
||||||
|
|
||||||
// MESSAGE TO BUSINESS TIME
|
// MESSAGE TO BUSINESS TIME
|
||||||
const businessTime = await isOutBusinessTime(number);
|
const businessTime = await isOutBusinessTime();
|
||||||
|
|
||||||
if (businessTime && businessTime.set) {
|
if (businessTime && businessTime.set) {
|
||||||
objs.push({ type: "businessTime", msg: businessTime.msg });
|
objs.push({ type: "businessTime", msg: businessTime.msg });
|
||||||
|
@ -1075,17 +734,4 @@ const outOfService = async (number: string) => {
|
||||||
return objs;
|
return objs;
|
||||||
};
|
};
|
||||||
|
|
||||||
export {
|
export { wbotMessageListener, handleMessage, handleMsgAck, lst };
|
||||||
wbotMessageListener,
|
|
||||||
handleMessage,
|
|
||||||
handleMsgAck,
|
|
||||||
lst,
|
|
||||||
verifyMessage,
|
|
||||||
verifyMediaMessage,
|
|
||||||
verifyContact,
|
|
||||||
isValidMsg,
|
|
||||||
mediaTypeWhatsappOfficial
|
|
||||||
};
|
|
||||||
async function whatsappInfo(whatsappId: string | number) {
|
|
||||||
return await Whatsapp.findByPk(whatsappId);
|
|
||||||
}
|
|
||||||
|
|
|
@ -13,9 +13,6 @@ interface Request {
|
||||||
farewellMessage?: string;
|
farewellMessage?: string;
|
||||||
status?: string;
|
status?: string;
|
||||||
isDefault?: boolean;
|
isDefault?: boolean;
|
||||||
phoneNumberId?: string;
|
|
||||||
wabaId?: string;
|
|
||||||
isOfficial?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Response {
|
interface Response {
|
||||||
|
@ -32,11 +29,10 @@ const CreateWhatsAppService = async ({
|
||||||
greetingMessage,
|
greetingMessage,
|
||||||
farewellMessage,
|
farewellMessage,
|
||||||
isDefault = false,
|
isDefault = false,
|
||||||
isOfficial = false,
|
|
||||||
phoneNumberId,
|
|
||||||
wabaId
|
|
||||||
}: Request): Promise<Response> => {
|
}: Request): Promise<Response> => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const schema = Yup.object().shape({
|
const schema = Yup.object().shape({
|
||||||
name: Yup.string()
|
name: Yup.string()
|
||||||
.required()
|
.required()
|
||||||
|
@ -52,11 +48,12 @@ const CreateWhatsAppService = async ({
|
||||||
return !nameExists;
|
return !nameExists;
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
isDefault: Yup.boolean().required()
|
isDefault: Yup.boolean().required(),
|
||||||
|
urlApi: Yup.string().required()
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await schema.validate({ name, status, isDefault });
|
await schema.validate({ name, status, isDefault, urlApi });
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
throw new AppError(err.message);
|
throw new AppError(err.message);
|
||||||
}
|
}
|
||||||
|
@ -73,6 +70,7 @@ const CreateWhatsAppService = async ({
|
||||||
});
|
});
|
||||||
if (oldDefaultWhatsapp) {
|
if (oldDefaultWhatsapp) {
|
||||||
await oldDefaultWhatsapp.update({ isDefault: false });
|
await oldDefaultWhatsapp.update({ isDefault: false });
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,12 +78,6 @@ const CreateWhatsAppService = async ({
|
||||||
throw new AppError("ERR_WAPP_GREETING_REQUIRED");
|
throw new AppError("ERR_WAPP_GREETING_REQUIRED");
|
||||||
}
|
}
|
||||||
|
|
||||||
const classification = isOfficial ? "GREEN" : null;
|
|
||||||
|
|
||||||
if (isOfficial) {
|
|
||||||
status = "CONNECTED";
|
|
||||||
}
|
|
||||||
|
|
||||||
const whatsapp = await Whatsapp.create(
|
const whatsapp = await Whatsapp.create(
|
||||||
{
|
{
|
||||||
name,
|
name,
|
||||||
|
@ -94,11 +86,7 @@ const CreateWhatsAppService = async ({
|
||||||
urlApi,
|
urlApi,
|
||||||
greetingMessage,
|
greetingMessage,
|
||||||
farewellMessage,
|
farewellMessage,
|
||||||
isDefault,
|
isDefault
|
||||||
phoneNumberId,
|
|
||||||
wabaId,
|
|
||||||
isOfficial,
|
|
||||||
classification
|
|
||||||
},
|
},
|
||||||
{ include: ["queues"] }
|
{ include: ["queues"] }
|
||||||
);
|
);
|
||||||
|
@ -106,10 +94,13 @@ const CreateWhatsAppService = async ({
|
||||||
await AssociateWhatsappQueue(whatsapp, queueIds);
|
await AssociateWhatsappQueue(whatsapp, queueIds);
|
||||||
|
|
||||||
return { whatsapp, oldDefaultWhatsapp };
|
return { whatsapp, oldDefaultWhatsapp };
|
||||||
} catch (error: any) {
|
|
||||||
console.error("===> Error on CreateWhatsAppService.ts file: \n", error);
|
} catch (error: any) {
|
||||||
|
console.error('===> Error on CreateWhatsAppService.ts file: \n', error)
|
||||||
throw new AppError(error.message);
|
throw new AppError(error.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CreateWhatsAppService;
|
export default CreateWhatsAppService;
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
import { Sequelize } from "sequelize";
|
|
||||||
import Whatsapp from "../../models/Whatsapp";
|
|
||||||
import WhatsappQueue from "../../models/WhatsappQueue";
|
|
||||||
const dbConfig = require("../../config/database");
|
|
||||||
const { QueryTypes } = require("sequelize");
|
|
||||||
|
|
||||||
const sequelize = new Sequelize(dbConfig);
|
|
||||||
|
|
||||||
const ListWhatsAppsForQueueService = async (queueId: number | string): Promise<any> => {
|
|
||||||
const distinctWhatsapps = await sequelize.query(
|
|
||||||
`SELECT w.id, w.number, w.status, wq.whatsappId, wq.queueId
|
|
||||||
FROM Whatsapps w
|
|
||||||
JOIN WhatsappQueues wq ON w.id = wq.whatsappId AND wq.queueId = ${queueId}
|
|
||||||
GROUP BY w.number;`,
|
|
||||||
{ type: QueryTypes.SELECT }
|
|
||||||
);
|
|
||||||
|
|
||||||
return distinctWhatsapps;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ListWhatsAppsForQueueService;
|
|
||||||
|
|
|
@ -12,14 +12,14 @@ const ListWhatsAppsNumber = async (
|
||||||
if (status) {
|
if (status) {
|
||||||
whatsapps = await Whatsapp.findAll({
|
whatsapps = await Whatsapp.findAll({
|
||||||
raw: true,
|
raw: true,
|
||||||
where: { number: whatsapp.number, status: status, },
|
where: { number: whatsapp.number, status: status },
|
||||||
attributes: ["id", "number", "status", "isDefault", "url", 'isOfficial']
|
attributes: ["id", "number", "status", "isDefault", "url"]
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
whatsapps = await Whatsapp.findAll({
|
whatsapps = await Whatsapp.findAll({
|
||||||
raw: true,
|
raw: true,
|
||||||
where: { number: whatsapp.number },
|
where: { number: whatsapp.number },
|
||||||
attributes: ["id", "number", "status", "isDefault", "url", 'isOfficial']
|
attributes: ["id", "number", "status", "isDefault", "url"]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,46 +2,19 @@ import Whatsapp from "../../models/Whatsapp";
|
||||||
import AppError from "../../errors/AppError";
|
import AppError from "../../errors/AppError";
|
||||||
import Queue from "../../models/Queue";
|
import Queue from "../../models/Queue";
|
||||||
|
|
||||||
const ShowWhatsAppService = async (
|
const ShowWhatsAppService = async (id: string | number): Promise<Whatsapp> => {
|
||||||
id: string | number | null,
|
const whatsapp = await Whatsapp.findByPk(id, {
|
||||||
whatsAppOfficial?: any
|
include: [
|
||||||
): Promise<Whatsapp> => {
|
{
|
||||||
let whatsapp;
|
model: Queue,
|
||||||
|
as: "queues",
|
||||||
|
attributes: ["id", "name", "color", "greetingMessage"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
order: [["queues", "id", "ASC"]]
|
||||||
|
});
|
||||||
|
|
||||||
if (id) {
|
// console.log('kkkkkkkkkkkkkkkkkkkk: ', whatsapp)
|
||||||
whatsapp = await Whatsapp.findByPk(id, {
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
model: Queue,
|
|
||||||
as: "queues",
|
|
||||||
attributes: [
|
|
||||||
"id",
|
|
||||||
"name",
|
|
||||||
"color",
|
|
||||||
"greetingMessage",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
order: [["queues", "id", "ASC"]]
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
whatsapp = await Whatsapp.findOne({
|
|
||||||
where: { number: whatsAppOfficial?.number },
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
model: Queue,
|
|
||||||
as: "queues",
|
|
||||||
attributes: [
|
|
||||||
"id",
|
|
||||||
"name",
|
|
||||||
"color",
|
|
||||||
"greetingMessage",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
order: [["queues", "id", "ASC"]]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!whatsapp) {
|
if (!whatsapp) {
|
||||||
throw new AppError("ERR_NO_WAPP_FOUND", 404);
|
throw new AppError("ERR_NO_WAPP_FOUND", 404);
|
||||||
|
|
|
@ -9,6 +9,8 @@ import AssociateWhatsappQueue from "./AssociateWhatsappQueue";
|
||||||
import { getWbot } from "../../libs/wbot";
|
import { getWbot } from "../../libs/wbot";
|
||||||
import { restartWhatsSession } from "../../helpers/RestartWhatsSession";
|
import { restartWhatsSession } from "../../helpers/RestartWhatsSession";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
interface WhatsappData {
|
interface WhatsappData {
|
||||||
name?: string;
|
name?: string;
|
||||||
url?: string;
|
url?: string;
|
||||||
|
@ -16,9 +18,6 @@ interface WhatsappData {
|
||||||
status?: string;
|
status?: string;
|
||||||
session?: string;
|
session?: string;
|
||||||
isDefault?: boolean;
|
isDefault?: boolean;
|
||||||
isOfficial?: boolean;
|
|
||||||
phoneNumberId?: string;
|
|
||||||
wabaId?: string;
|
|
||||||
greetingMessage?: string;
|
greetingMessage?: string;
|
||||||
farewellMessage?: string;
|
farewellMessage?: string;
|
||||||
queueIds?: number[];
|
queueIds?: number[];
|
||||||
|
@ -38,20 +37,19 @@ const UpdateWhatsAppService = async ({
|
||||||
whatsappData,
|
whatsappData,
|
||||||
whatsappId
|
whatsappId
|
||||||
}: Request): Promise<Response> => {
|
}: Request): Promise<Response> => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const schema = Yup.object().shape({
|
const schema = Yup.object().shape({
|
||||||
name: Yup.string().min(2),
|
name: Yup.string().min(2),
|
||||||
status: Yup.string(),
|
status: Yup.string(),
|
||||||
isDefault: Yup.boolean()
|
isDefault: Yup.boolean()
|
||||||
});
|
});
|
||||||
|
|
||||||
let {
|
const {
|
||||||
name,
|
name,
|
||||||
status,
|
status,
|
||||||
isDefault,
|
isDefault,
|
||||||
phoneNumberId,
|
|
||||||
wabaId,
|
|
||||||
isOfficial,
|
|
||||||
url,
|
url,
|
||||||
urlApi,
|
urlApi,
|
||||||
session,
|
session,
|
||||||
|
@ -60,6 +58,8 @@ const UpdateWhatsAppService = async ({
|
||||||
queueIds = []
|
queueIds = []
|
||||||
} = whatsappData;
|
} = whatsappData;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await schema.validate({ name, status, isDefault });
|
await schema.validate({ name, status, isDefault });
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
|
@ -85,23 +85,10 @@ const UpdateWhatsAppService = async ({
|
||||||
|
|
||||||
// console.log('############## whatsapp: ', JSON.parse(JSON.stringify(whatsapp)))
|
// console.log('############## whatsapp: ', JSON.parse(JSON.stringify(whatsapp)))
|
||||||
|
|
||||||
if (
|
if (name && !name.includes(whatsapp.number) && whatsapp.status === 'CONNECTED') {
|
||||||
name &&
|
|
||||||
!name.includes(whatsapp.number) &&
|
|
||||||
whatsapp.status === "CONNECTED" &&
|
|
||||||
!whatsapp.isOfficial
|
|
||||||
) {
|
|
||||||
throw new AppError("ERR_WAPP_WRONG_SESSION_NAME");
|
throw new AppError("ERR_WAPP_WRONG_SESSION_NAME");
|
||||||
}
|
|
||||||
|
|
||||||
const classification = isOfficial ? "GREEN" : null;
|
|
||||||
|
|
||||||
if (isOfficial) {
|
|
||||||
status = "CONNECTED";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (whatsapp.isOfficial && !isOfficial) {
|
|
||||||
status = "OPENING";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await whatsapp.update({
|
await whatsapp.update({
|
||||||
|
@ -112,11 +99,7 @@ const UpdateWhatsAppService = async ({
|
||||||
urlApi,
|
urlApi,
|
||||||
greetingMessage,
|
greetingMessage,
|
||||||
farewellMessage,
|
farewellMessage,
|
||||||
isDefault,
|
isDefault
|
||||||
isOfficial,
|
|
||||||
phoneNumberId,
|
|
||||||
wabaId,
|
|
||||||
classification
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// await insertOrUpeateWhatsCache(`whatsapp:${whatsapp.id}`, {
|
// await insertOrUpeateWhatsCache(`whatsapp:${whatsapp.id}`, {
|
||||||
|
@ -131,10 +114,12 @@ const UpdateWhatsAppService = async ({
|
||||||
await AssociateWhatsappQueue(whatsapp, queueIds);
|
await AssociateWhatsappQueue(whatsapp, queueIds);
|
||||||
|
|
||||||
return { whatsapp, oldDefaultWhatsapp };
|
return { whatsapp, oldDefaultWhatsapp };
|
||||||
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error("===> Error on UpdateWhatsAppService.ts file: \n", error);
|
console.error('===> Error on UpdateWhatsAppService.ts file: \n', error)
|
||||||
throw new AppError(error.message);
|
throw new AppError(error.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default UpdateWhatsAppService;
|
export default UpdateWhatsAppService;
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
REACT_APP_BACKEND_URL = http://localhost:8080/
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useState, useEffect, useContext } from 'react'
|
import React, { useState, useEffect, } 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'
|
||||||
|
@ -12,7 +12,7 @@ import DateFnsUtils from '@date-io/date-fns'
|
||||||
|
|
||||||
import ptBrLocale from "date-fns/locale/pt-BR"
|
import ptBrLocale from "date-fns/locale/pt-BR"
|
||||||
|
|
||||||
import { WhatsAppsContext } from "../../context/WhatsApp/WhatsAppsContext"
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
MuiPickersUtilsProvider,
|
MuiPickersUtilsProvider,
|
||||||
|
@ -28,16 +28,12 @@ import {
|
||||||
TextField,
|
TextField,
|
||||||
Switch,
|
Switch,
|
||||||
FormControlLabel,
|
FormControlLabel,
|
||||||
Divider,
|
|
||||||
} from '@material-ui/core'
|
} from '@material-ui/core'
|
||||||
|
|
||||||
import api from '../../services/api'
|
import api from '../../services/api'
|
||||||
import { i18n } from '../../translate/i18n'
|
import { i18n } from '../../translate/i18n'
|
||||||
import toastError from '../../errors/toastError'
|
import toastError from '../../errors/toastError'
|
||||||
|
|
||||||
import Select from "@material-ui/core/Select"
|
|
||||||
import MenuItem from "@material-ui/core/MenuItem"
|
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
root: {
|
root: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
@ -91,35 +87,13 @@ const ConfigModal = ({ open, onClose, change }) => {
|
||||||
enableWeekendMessage: false
|
enableWeekendMessage: false
|
||||||
}
|
}
|
||||||
|
|
||||||
const { whatsApps } = useContext(WhatsAppsContext)
|
|
||||||
const [selectedNumber, setSelectedNumber] = useState('')
|
|
||||||
|
|
||||||
const [config, setConfig] = useState(initialState)
|
const [config, setConfig] = useState(initialState)
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
console.log('selectedNumber: ', selectedNumber)
|
|
||||||
|
|
||||||
if (selectedNumber?.trim().length === 0) {
|
|
||||||
setConfig(initialState)
|
|
||||||
}
|
|
||||||
|
|
||||||
}, [selectedNumber])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchSession = async () => {
|
const fetchSession = async () => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// const { data } = await api.get('/settings')
|
const { data } = await api.get('/settings')
|
||||||
|
|
||||||
if (!selectedNumber) return
|
|
||||||
|
|
||||||
const { data } = await api.get(`/settings/ticket/${selectedNumber}`)
|
|
||||||
|
|
||||||
if (data?.config && data.config.length === 0) {
|
|
||||||
setConfig(initialState)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const outBusinessHours = data.config.find((c) => c.key === "outBusinessHours")
|
const outBusinessHours = data.config.find((c) => c.key === "outBusinessHours")
|
||||||
const ticketExpiration = data.config.find((c) => c.key === "ticketExpiration")
|
const ticketExpiration = data.config.find((c) => c.key === "ticketExpiration")
|
||||||
|
@ -153,12 +127,11 @@ const ConfigModal = ({ open, onClose, change }) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fetchSession()
|
fetchSession()
|
||||||
}, [change, selectedNumber])
|
}, [change])
|
||||||
|
|
||||||
const handleSaveConfig = async (values) => {
|
const handleSaveConfig = async (values) => {
|
||||||
|
|
||||||
values = {
|
values = {
|
||||||
number: selectedNumber,
|
|
||||||
outBusinessHours: {
|
outBusinessHours: {
|
||||||
startTime: values.startTimeBus,
|
startTime: values.startTimeBus,
|
||||||
endTime: values.endTimeBus,
|
endTime: values.endTimeBus,
|
||||||
|
@ -174,7 +147,7 @@ const ConfigModal = ({ open, onClose, change }) => {
|
||||||
message: values.weekendMessage,
|
message: values.weekendMessage,
|
||||||
value: values.enableWeekendMessage ? 'enabled' : 'disabled'
|
value: values.enableWeekendMessage ? 'enabled' : 'disabled'
|
||||||
},
|
},
|
||||||
saturday: {
|
saturday:{
|
||||||
value: values.checkboxSaturdayValue ? 'enabled' : 'disabled'
|
value: values.checkboxSaturdayValue ? 'enabled' : 'disabled'
|
||||||
},
|
},
|
||||||
sunday: {
|
sunday: {
|
||||||
|
@ -238,39 +211,6 @@ const ConfigModal = ({ open, onClose, change }) => {
|
||||||
|
|
||||||
<DialogContent dividers>
|
<DialogContent dividers>
|
||||||
|
|
||||||
<div>
|
|
||||||
<Select
|
|
||||||
value={selectedNumber}
|
|
||||||
onChange={(e) => setSelectedNumber(e.target.value)}
|
|
||||||
label={i18n.t("transferTicketModal.fieldQueuePlaceholder")}
|
|
||||||
required
|
|
||||||
>
|
|
||||||
<MenuItem style={{ background: "white", }} value={''}> </MenuItem>
|
|
||||||
|
|
||||||
{whatsApps.reduce((acc, curr) => {
|
|
||||||
const existingObject = acc.find(item => item.number === curr.number)
|
|
||||||
|
|
||||||
if (!existingObject) {
|
|
||||||
acc.push(curr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return acc
|
|
||||||
}, []).map((whatsapp) => (
|
|
||||||
<MenuItem
|
|
||||||
key={whatsapp.id}
|
|
||||||
value={whatsapp.number}
|
|
||||||
>
|
|
||||||
{whatsapp.number}
|
|
||||||
</MenuItem>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<Divider />
|
|
||||||
<br />
|
|
||||||
|
|
||||||
<div className={classes.multFieldLine}>
|
<div className={classes.multFieldLine}>
|
||||||
<Field
|
<Field
|
||||||
component={TimePicker}
|
component={TimePicker}
|
||||||
|
|
|
@ -1,26 +1,27 @@
|
||||||
import React, { useState, useEffect, useContext, useRef, useCallback } from "react"
|
import React, { useState, useEffect, useContext, useRef, useCallback } from "react";
|
||||||
import { useHistory } from "react-router-dom"
|
import { useHistory } from "react-router-dom";
|
||||||
import { toast } from "react-toastify"
|
import { toast } from "react-toastify";
|
||||||
|
|
||||||
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";
|
||||||
import Select from "@material-ui/core/Select"
|
import Select from "@material-ui/core/Select";
|
||||||
import FormControl from "@material-ui/core/FormControl"
|
import FormControl from "@material-ui/core/FormControl";
|
||||||
import InputLabel from "@material-ui/core/InputLabel"
|
import InputLabel from "@material-ui/core/InputLabel";
|
||||||
import MenuItem from "@material-ui/core/MenuItem"
|
import MenuItem from "@material-ui/core/MenuItem";
|
||||||
import { makeStyles } from "@material-ui/core"
|
import LinearProgress from "@material-ui/core/LinearProgress";
|
||||||
|
import { makeStyles } from "@material-ui/core";
|
||||||
|
|
||||||
import DialogActions from "@material-ui/core/DialogActions"
|
import DialogActions from "@material-ui/core/DialogActions";
|
||||||
import DialogContent from "@material-ui/core/DialogContent"
|
import DialogContent from "@material-ui/core/DialogContent";
|
||||||
import DialogTitle from "@material-ui/core/DialogTitle"
|
import DialogTitle from "@material-ui/core/DialogTitle";
|
||||||
|
|
||||||
import { i18n } from "../../translate/i18n"
|
import { i18n } from "../../translate/i18n";
|
||||||
import ButtonWithSpinner from "../ButtonWithSpinner"
|
import ButtonWithSpinner from "../ButtonWithSpinner";
|
||||||
import { AuthContext } from "../../context/Auth/AuthContext"
|
import { AuthContext } from "../../context/Auth/AuthContext";
|
||||||
|
|
||||||
import toastError from "../../errors/toastError"
|
import toastError from "../../errors/toastError";
|
||||||
|
|
||||||
import api from "../../services/api"
|
import api from "../../services/api";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
maxWidth: {
|
maxWidth: {
|
||||||
|
@ -32,59 +33,30 @@ const useStyles = makeStyles((theme) => ({
|
||||||
linearProgress: {
|
linearProgress: {
|
||||||
marginTop: "5px"
|
marginTop: "5px"
|
||||||
}
|
}
|
||||||
}))
|
}));
|
||||||
|
|
||||||
const ContactCreateTicketModal = ({ modalOpen, onClose, contactId }) => {
|
const ContactCreateTicketModal = ({ modalOpen, onClose, contactId }) => {
|
||||||
const { user } = useContext(AuthContext)
|
const { user } = useContext(AuthContext);
|
||||||
|
|
||||||
let isMounted = useRef(true)
|
let isMounted = useRef(true)
|
||||||
|
|
||||||
const history = useHistory()
|
const history = useHistory();
|
||||||
const [queues, setQueues] = useState([])
|
const [queues, setQueues] = useState([]);
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false);
|
||||||
const [selectedQueue, setSelectedQueue] = useState('')
|
const [selectedQueue, setSelectedQueue] = useState('');
|
||||||
const [itemHover, setItemHover] = useState(-1)
|
const [itemHover, setItemHover] = useState(-1)
|
||||||
|
const classes = useStyles();
|
||||||
const [selectedWhatsId, setSelectedWhatsId] = useState()
|
|
||||||
const [whatsQueue, setWhatsQueue] = useState()
|
|
||||||
const [disabled, setDisabled] = useState(false)
|
|
||||||
|
|
||||||
const classes = useStyles()
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const userQueues = user.queues.map(({ id, name, color }) => { return { id, name, color } })
|
||||||
const delayDebounceFn = setTimeout(() => {
|
if (userQueues.length === 1) setSelectedQueue(userQueues[0].id)
|
||||||
|
setQueues(userQueues)
|
||||||
const fetchMatchQueueUserOfficialWhatsapp = async () => {
|
}, [user]);
|
||||||
try {
|
|
||||||
|
|
||||||
const { data } = await api.get("/whatsapp/official/matchQueueUser", { params: { userId: user.id, queueId: selectedQueue }, })
|
|
||||||
|
|
||||||
setQueues(data)
|
|
||||||
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fetchMatchQueueUserOfficialWhatsapp()
|
|
||||||
|
|
||||||
}, 500)
|
|
||||||
return () => clearTimeout(delayDebounceFn)
|
|
||||||
|
|
||||||
}, [user, selectedQueue])
|
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
onClose()
|
onClose();
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleSaveTicket = useCallback(async (contactId, userId, queueId, selectedWhatsId, whatsQueue, queues) => {
|
|
||||||
|
|
||||||
if (queues && queues.length === 1 && queues[0].disable) {
|
|
||||||
toast.warn('Não é possível criar um Ticket porque a fila a qual você esta adicionado(a) não está associado a nenhum numero!')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const handleSaveTicket = useCallback(async (contactId, userId, queueId) => {
|
||||||
if (!contactId || !userId) {
|
if (!contactId || !userId) {
|
||||||
console.log("Missing contactId or userId")
|
console.log("Missing contactId or userId")
|
||||||
return
|
return
|
||||||
|
@ -93,12 +65,8 @@ const ContactCreateTicketModal = ({ modalOpen, onClose, contactId }) => {
|
||||||
toast.warning("Nenhuma Fila Selecionada")
|
toast.warning("Nenhuma Fila Selecionada")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (isMounted.current) setLoading(true)
|
if (isMounted.current) setLoading(true);
|
||||||
|
|
||||||
if (whatsQueue && !selectedWhatsId) {
|
|
||||||
toast.warn('Selecione um numero!')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const delayDebounceFn = setTimeout(() => {
|
const delayDebounceFn = setTimeout(() => {
|
||||||
const ticketCreate = async () => {
|
const ticketCreate = async () => {
|
||||||
|
@ -108,77 +76,32 @@ const ContactCreateTicketModal = ({ modalOpen, onClose, contactId }) => {
|
||||||
userId: userId,
|
userId: userId,
|
||||||
queueId: queueId,
|
queueId: queueId,
|
||||||
status: "open",
|
status: "open",
|
||||||
whatsappId: selectedWhatsId
|
});
|
||||||
})
|
history.push(`/tickets/${ticket.id}`);
|
||||||
history.push(`/tickets/${ticket.id}`)
|
|
||||||
|
|
||||||
setWhatsQueue(null)
|
|
||||||
setSelectedWhatsId(null)
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
toastError(err)
|
toastError(err);
|
||||||
}
|
}
|
||||||
if (isMounted.current) setLoading(false)
|
if (isMounted.current) setLoading(false);
|
||||||
|
|
||||||
}
|
};
|
||||||
ticketCreate()
|
ticketCreate();
|
||||||
}, 300)
|
}, 300);
|
||||||
return () => clearTimeout(delayDebounceFn)
|
return () => clearTimeout(delayDebounceFn);
|
||||||
|
|
||||||
}, [history])
|
}, [history])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (modalOpen && queues.length <= 1) {
|
||||||
if (selectedQueue && (selectedQueue.length === 0 || !selectedQueue)) {
|
handleSaveTicket(contactId, user.id, selectedQueue)
|
||||||
setDisabled(true)
|
|
||||||
setWhatsQueue(null)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Array.isArray(whatsQueue)) {
|
|
||||||
setSelectedWhatsId(null)
|
|
||||||
setWhatsQueue(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
isMounted.current = false
|
isMounted.current = false;
|
||||||
}
|
};
|
||||||
}, [modalOpen, contactId, user.id, selectedQueue, handleSaveTicket, queues.length, selectedWhatsId, whatsQueue, queues])
|
}, [modalOpen, contactId, user.id, selectedQueue, handleSaveTicket, queues.length]);
|
||||||
|
|
||||||
|
if (modalOpen && queues.length <= 1) {
|
||||||
useEffect(() => {
|
return <LinearProgress />
|
||||||
|
}
|
||||||
if (!selectedQueue) return
|
|
||||||
|
|
||||||
setDisabled(true)
|
|
||||||
|
|
||||||
const delayDebounceFn = setTimeout(() => {
|
|
||||||
|
|
||||||
const fetChMatchQueueOfficialWhatsapp = async () => {
|
|
||||||
try {
|
|
||||||
|
|
||||||
const { data } = await api.get("/whatsapp/official/matchQueue", { params: { userId: user.id, queueId: selectedQueue }, })
|
|
||||||
|
|
||||||
console.log('WHATSAPP DATA: ', data)
|
|
||||||
|
|
||||||
setWhatsQueue(data)
|
|
||||||
|
|
||||||
setDisabled(false)
|
|
||||||
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fetChMatchQueueOfficialWhatsapp()
|
|
||||||
|
|
||||||
}, 500)
|
|
||||||
return () => clearTimeout(delayDebounceFn)
|
|
||||||
|
|
||||||
}, [selectedQueue, user.id])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
console.log('selectedWhatsId: ', selectedWhatsId)
|
|
||||||
console.log('whatsQuee: ', whatsQueue)
|
|
||||||
}, [whatsQueue, selectedWhatsId])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={modalOpen} onClose={handleClose} maxWidth="xs" scroll="paper" classes={{ paper: classes.paper }}>
|
<Dialog open={modalOpen} onClose={handleClose} maxWidth="xs" scroll="paper" classes={{ paper: classes.paper }}>
|
||||||
|
@ -194,10 +117,9 @@ const ContactCreateTicketModal = ({ modalOpen, onClose, contactId }) => {
|
||||||
label={i18n.t("Filas")}
|
label={i18n.t("Filas")}
|
||||||
>
|
>
|
||||||
<MenuItem value={''}> </MenuItem>
|
<MenuItem value={''}> </MenuItem>
|
||||||
{queues.map(({ id, color, name, disable }) => (
|
{queues.map(({ id, color, name }) => (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
key={id}
|
key={id}
|
||||||
disabled={disable}
|
|
||||||
value={id}
|
value={id}
|
||||||
onMouseEnter={() => setItemHover(id)}
|
onMouseEnter={() => setItemHover(id)}
|
||||||
onMouseLeave={() => setItemHover(-1)}
|
onMouseLeave={() => setItemHover(-1)}
|
||||||
|
@ -209,31 +131,6 @@ const ContactCreateTicketModal = ({ modalOpen, onClose, contactId }) => {
|
||||||
</Select>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|
||||||
{whatsQueue && Array.isArray(whatsQueue) ?
|
|
||||||
<DialogContent dividers>
|
|
||||||
<FormControl variant="outlined" className={classes.maxWidth}>
|
|
||||||
<InputLabel>{i18n.t("Selecionar Numero")}</InputLabel>
|
|
||||||
<Select
|
|
||||||
value={selectedWhatsId}
|
|
||||||
onChange={(e) => setSelectedWhatsId(e.target.value)}
|
|
||||||
label={i18n.t("Numeros")}
|
|
||||||
>
|
|
||||||
<MenuItem value={''}> </MenuItem>
|
|
||||||
{whatsQueue.map(({ id, number, phoneNumberId }) => (
|
|
||||||
<MenuItem
|
|
||||||
key={id}
|
|
||||||
value={id}
|
|
||||||
>{phoneNumberId ? `${number} OFICIAL` : `${number}`}</MenuItem>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
</DialogContent>
|
|
||||||
: <></>
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button
|
<Button
|
||||||
onClick={handleClose}
|
onClick={handleClose}
|
||||||
|
@ -244,17 +141,16 @@ const ContactCreateTicketModal = ({ modalOpen, onClose, contactId }) => {
|
||||||
{i18n.t("newTicketModal.buttons.cancel")}
|
{i18n.t("newTicketModal.buttons.cancel")}
|
||||||
</Button>
|
</Button>
|
||||||
<ButtonWithSpinner
|
<ButtonWithSpinner
|
||||||
onClick={() => handleSaveTicket(contactId, user.id, selectedQueue, selectedWhatsId, whatsQueue, queues)}
|
onClick={() => handleSaveTicket(contactId, user.id, selectedQueue)}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
loading={loading}
|
loading={loading}
|
||||||
disabled={disabled}
|
|
||||||
>
|
>
|
||||||
{i18n.t("newTicketModal.buttons.ok")}
|
{i18n.t("newTicketModal.buttons.ok")}
|
||||||
</ButtonWithSpinner>
|
</ButtonWithSpinner>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default ContactCreateTicketModal
|
export default ContactCreateTicketModal;
|
|
@ -1,50 +1,47 @@
|
||||||
import React, { useState, useEffect, useContext, useRef } from "react"
|
import React, { useState, useEffect, useContext, useRef } from "react";
|
||||||
import "emoji-mart/css/emoji-mart.css"
|
import "emoji-mart/css/emoji-mart.css";
|
||||||
import { useParams } from "react-router-dom"
|
import { useParams } from "react-router-dom";
|
||||||
import { Picker } from "emoji-mart"
|
import { Picker } from "emoji-mart";
|
||||||
import MicRecorder from "mic-recorder-to-mp3"
|
import MicRecorder from "mic-recorder-to-mp3";
|
||||||
import clsx from "clsx"
|
import clsx from "clsx";
|
||||||
|
|
||||||
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";
|
||||||
import InputBase from "@material-ui/core/InputBase"
|
import InputBase from "@material-ui/core/InputBase";
|
||||||
import CircularProgress from "@material-ui/core/CircularProgress"
|
import CircularProgress from "@material-ui/core/CircularProgress";
|
||||||
import { green } from "@material-ui/core/colors"
|
import { green } from "@material-ui/core/colors";
|
||||||
import AttachFileIcon from "@material-ui/icons/AttachFile"
|
import AttachFileIcon from "@material-ui/icons/AttachFile";
|
||||||
import IconButton from "@material-ui/core/IconButton"
|
import IconButton from "@material-ui/core/IconButton";
|
||||||
import MoreVert from "@material-ui/icons/MoreVert"
|
import MoreVert from "@material-ui/icons/MoreVert";
|
||||||
import MoodIcon from "@material-ui/icons/Mood"
|
import MoodIcon from "@material-ui/icons/Mood";
|
||||||
import SendIcon from "@material-ui/icons/Send"
|
import SendIcon from "@material-ui/icons/Send";
|
||||||
import CancelIcon from "@material-ui/icons/Cancel"
|
import CancelIcon from "@material-ui/icons/Cancel";
|
||||||
import ClearIcon from "@material-ui/icons/Clear"
|
import ClearIcon from "@material-ui/icons/Clear";
|
||||||
import MicIcon from "@material-ui/icons/Mic"
|
import MicIcon from "@material-ui/icons/Mic";
|
||||||
import CheckCircleOutlineIcon from "@material-ui/icons/CheckCircleOutline"
|
import CheckCircleOutlineIcon from "@material-ui/icons/CheckCircleOutline";
|
||||||
import HighlightOffIcon from "@material-ui/icons/HighlightOff"
|
import HighlightOffIcon from "@material-ui/icons/HighlightOff";
|
||||||
import {
|
import {
|
||||||
FormControlLabel,
|
FormControlLabel,
|
||||||
Hidden,
|
Hidden,
|
||||||
Menu,
|
Menu,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
Switch,
|
Switch,
|
||||||
} from "@material-ui/core"
|
} from "@material-ui/core";
|
||||||
import ClickAwayListener from "@material-ui/core/ClickAwayListener"
|
import ClickAwayListener from "@material-ui/core/ClickAwayListener";
|
||||||
|
|
||||||
import { i18n } from "../../translate/i18n"
|
import { i18n } from "../../translate/i18n";
|
||||||
import api from "../../services/api"
|
import api from "../../services/api";
|
||||||
import RecordingTimer from "./RecordingTimer"
|
import RecordingTimer from "./RecordingTimer";
|
||||||
import { ReplyMessageContext } from "../../context/ReplyingMessage/ReplyingMessageContext"
|
import { ReplyMessageContext } from "../../context/ReplyingMessage/ReplyingMessageContext";
|
||||||
import { AuthContext } from "../../context/Auth/AuthContext"
|
import { AuthContext } from "../../context/Auth/AuthContext";
|
||||||
import { useLocalStorage } from "../../hooks/useLocalStorage"
|
import { useLocalStorage } from "../../hooks/useLocalStorage";
|
||||||
import toastError from "../../errors/toastError"
|
import toastError from "../../errors/toastError";
|
||||||
|
|
||||||
// import TicketsManager from "../../components/TicketsManager/";
|
// import TicketsManager from "../../components/TicketsManager/";
|
||||||
|
|
||||||
import { TabTicketContext } from "../../context/TabTicketHeaderOption/TabTicketHeaderOption"
|
import { TabTicketContext } from "../../context/TabTicketHeaderOption/TabTicketHeaderOption";
|
||||||
import ModalTemplate from "../ModalTemplate"
|
|
||||||
|
|
||||||
import { render } from '@testing-library/react'
|
const Mp3Recorder = new MicRecorder({ bitRate: 128 });
|
||||||
|
|
||||||
const Mp3Recorder = new MicRecorder({ bitRate: 128 })
|
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
mainWrapper: {
|
mainWrapper: {
|
||||||
|
@ -206,83 +203,78 @@ const useStyles = makeStyles((theme) => ({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}))
|
}));
|
||||||
|
|
||||||
const MessageInput = ({ ticketStatus }) => {
|
const MessageInput = ({ ticketStatus }) => {
|
||||||
|
|
||||||
const { tabOption, setTabOption } = useContext(TabTicketContext)
|
const { tabOption, setTabOption } = useContext(TabTicketContext);
|
||||||
|
|
||||||
const classes = useStyles()
|
const classes = useStyles();
|
||||||
const { ticketId } = useParams()
|
const { ticketId } = useParams();
|
||||||
|
|
||||||
const [medias, setMedias] = useState([])
|
const [medias, setMedias] = useState([]);
|
||||||
const [inputMessage, setInputMessage] = useState("")
|
const [inputMessage, setInputMessage] = useState("");
|
||||||
const [showEmoji, setShowEmoji] = useState(false)
|
const [showEmoji, setShowEmoji] = useState(false);
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false);
|
||||||
const [recording, setRecording] = useState(false)
|
const [recording, setRecording] = useState(false);
|
||||||
const [quickAnswers, setQuickAnswer] = useState([])
|
const [quickAnswers, setQuickAnswer] = useState([]);
|
||||||
const [typeBar, setTypeBar] = useState(false)
|
const [typeBar, setTypeBar] = useState(false);
|
||||||
const inputRef = useRef()
|
const inputRef = useRef();
|
||||||
const [anchorEl, setAnchorEl] = useState(null)
|
const [anchorEl, setAnchorEl] = useState(null);
|
||||||
const { setReplyingMessage, replyingMessage } = useContext(ReplyMessageContext)
|
const { setReplyingMessage, replyingMessage } = useContext(ReplyMessageContext);
|
||||||
const { user } = useContext(AuthContext)
|
const { user } = useContext(AuthContext);
|
||||||
const [templates, setTemplates] = useState(null)
|
|
||||||
const [params, setParams] = useState(null)
|
|
||||||
|
|
||||||
const [signMessage, setSignMessage] = useLocalStorage("signOption", true)
|
|
||||||
|
|
||||||
const isRun = useRef(false)
|
|
||||||
|
|
||||||
|
const [signMessage, setSignMessage] = useLocalStorage("signOption", true);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
inputRef.current.focus()
|
inputRef.current.focus();
|
||||||
}, [replyingMessage])
|
}, [replyingMessage]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
inputRef.current.focus()
|
inputRef.current.focus();
|
||||||
return () => {
|
return () => {
|
||||||
setInputMessage("")
|
setInputMessage("");
|
||||||
setShowEmoji(false)
|
setShowEmoji(false);
|
||||||
setMedias([])
|
setMedias([]);
|
||||||
setReplyingMessage(null)
|
setReplyingMessage(null);
|
||||||
}
|
};
|
||||||
}, [ticketId, setReplyingMessage])
|
}, [ticketId, setReplyingMessage]);
|
||||||
|
|
||||||
const handleChangeInput = (e) => {
|
const handleChangeInput = (e) => {
|
||||||
setInputMessage(e.target.value)
|
setInputMessage(e.target.value);
|
||||||
handleLoadQuickAnswer(e.target.value)
|
handleLoadQuickAnswer(e.target.value);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleQuickAnswersClick = (value) => {
|
const handleQuickAnswersClick = (value) => {
|
||||||
setInputMessage(value)
|
setInputMessage(value);
|
||||||
setTypeBar(false)
|
setTypeBar(false);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleAddEmoji = (e) => {
|
const handleAddEmoji = (e) => {
|
||||||
let emoji = e.native
|
let emoji = e.native;
|
||||||
setInputMessage((prevState) => prevState + emoji)
|
setInputMessage((prevState) => prevState + emoji);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleChangeMedias = (e) => {
|
const handleChangeMedias = (e) => {
|
||||||
if (!e.target.files) {
|
if (!e.target.files) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectedMedias = Array.from(e.target.files)
|
const selectedMedias = Array.from(e.target.files);
|
||||||
setMedias(selectedMedias)
|
setMedias(selectedMedias);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleInputPaste = (e) => {
|
const handleInputPaste = (e) => {
|
||||||
if (e.clipboardData.files[0]) {
|
if (e.clipboardData.files[0]) {
|
||||||
|
|
||||||
console.log('clipboardData: ', e.clipboardData.files[0])
|
console.log('clipboardData: ', e.clipboardData.files[0])
|
||||||
setMedias([e.clipboardData.files[0]])
|
setMedias([e.clipboardData.files[0]]);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleUploadMedia = async (e) => {
|
const handleUploadMedia = async (e) => {
|
||||||
setLoading(true)
|
setLoading(true);
|
||||||
e.preventDefault()
|
e.preventDefault();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -290,171 +282,92 @@ const MessageInput = ({ ticketStatus }) => {
|
||||||
setTabOption('open')
|
setTabOption('open')
|
||||||
}
|
}
|
||||||
|
|
||||||
const formData = new FormData()
|
const formData = new FormData();
|
||||||
formData.append("fromMe", true)
|
formData.append("fromMe", true);
|
||||||
medias.forEach((media) => {
|
medias.forEach((media) => {
|
||||||
formData.append("medias", media)
|
formData.append("medias", media);
|
||||||
formData.append("body", media.name)
|
formData.append("body", media.name);
|
||||||
})
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { data } = await api.post(`/messages/${ticketId}`, formData)
|
await api.post(`/messages/${ticketId}`, formData);
|
||||||
|
|
||||||
console.log('DATA FROM SEND MESSAGE MEDIA: ', data)
|
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
toastError(err)
|
toastError(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
setLoading(false)
|
setLoading(false);
|
||||||
setMedias([])
|
setMedias([]);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleSendMessage = async (templateParams = null) => {
|
const handleSendMessage = async () => {
|
||||||
|
if (inputMessage.trim() === "") return;
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
console.log('templateParams: ', templateParams, ' | inputMessage: ', inputMessage)
|
|
||||||
|
|
||||||
if (inputMessage.trim() === "") return
|
|
||||||
setLoading(true)
|
|
||||||
|
|
||||||
if (tabOption === 'search') {
|
if (tabOption === 'search') {
|
||||||
setTabOption('open')
|
setTabOption('open')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (templateParams) {
|
const message = {
|
||||||
for (let key in templateParams) {
|
|
||||||
if (templateParams.hasOwnProperty(key)) {
|
|
||||||
// let value = templateParams[key]
|
|
||||||
// console.log('key: ', key, ' | ', 'VALUE: ', value)
|
|
||||||
|
|
||||||
if (key === '_reactName') {
|
|
||||||
templateParams = null
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let message = {
|
|
||||||
read: 1,
|
read: 1,
|
||||||
fromMe: true,
|
fromMe: true,
|
||||||
mediaUrl: "",
|
mediaUrl: "",
|
||||||
body: (signMessage && !templateParams) ? `*${user?.name}:*\n${inputMessage.trim()}` : inputMessage.trim(),
|
body: signMessage
|
||||||
quotedMsg: replyingMessage
|
? `*${user?.name}:*\n${inputMessage.trim()}`
|
||||||
}
|
: inputMessage.trim(),
|
||||||
|
quotedMsg: replyingMessage,
|
||||||
if (templateParams) {
|
};
|
||||||
message = { ...message, params: templateParams }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const { data } = await api.post(`/messages/${ticketId}`, message)
|
// console.log('message: ', message)
|
||||||
setParams(null)
|
await api.post(`/messages/${ticketId}`, message);
|
||||||
if (data && data?.data && Array.isArray(data.data)) {
|
|
||||||
setTemplates(data.data)
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
toastError(err)
|
toastError(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
setInputMessage("")
|
setInputMessage("");
|
||||||
setShowEmoji(false)
|
setShowEmoji(false);
|
||||||
setLoading(false)
|
setLoading(false);
|
||||||
setReplyingMessage(null)
|
setReplyingMessage(null);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
|
|
||||||
if (!params) return
|
|
||||||
|
|
||||||
const body_params = params.find(p => p?.type === 'BODY')
|
|
||||||
|
|
||||||
let { text } = body_params
|
|
||||||
|
|
||||||
console.log('PARAMS FROM MESSAGE INPUT: ', params, ' | text: ', text)
|
|
||||||
|
|
||||||
let body = text.match(/{{\d+}}/g)
|
|
||||||
|
|
||||||
if (body && body.length > 0) {
|
|
||||||
|
|
||||||
const { parameters } = body_params
|
|
||||||
|
|
||||||
for (const key in parameters) {
|
|
||||||
if (!isNaN(key)) {
|
|
||||||
const { index, text: body_text } = parameters[key]
|
|
||||||
text = text.replace(`{{${index}}}`, body_text)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
console.log('NEW TEXT: ', text)
|
|
||||||
setInputMessage(text)
|
|
||||||
|
|
||||||
}, [params])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
|
|
||||||
if (params) {
|
|
||||||
handleSendMessage(params)
|
|
||||||
}
|
|
||||||
|
|
||||||
}, [inputMessage, params])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
|
|
||||||
if (!templates) return
|
|
||||||
|
|
||||||
return render(<ModalTemplate
|
|
||||||
modal_header={'Escolha um template para iniciar o Atendimento'}
|
|
||||||
func={setParams}
|
|
||||||
templates={templates.map(({ id, name, components, language, }) => {
|
|
||||||
return { id, name, components, language, }
|
|
||||||
})}
|
|
||||||
ticketId={ticketId}
|
|
||||||
/>)
|
|
||||||
|
|
||||||
}, [templates])
|
|
||||||
|
|
||||||
const handleStartRecording = async () => {
|
const handleStartRecording = async () => {
|
||||||
|
|
||||||
setLoading(true)
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
await navigator.mediaDevices.getUserMedia({ audio: true })
|
await navigator.mediaDevices.getUserMedia({ audio: true });
|
||||||
await Mp3Recorder.start()
|
await Mp3Recorder.start();
|
||||||
setRecording(true)
|
setRecording(true);
|
||||||
setLoading(false)
|
setLoading(false);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
toastError(err)
|
toastError(err);
|
||||||
setLoading(false)
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleLoadQuickAnswer = async (value) => {
|
const handleLoadQuickAnswer = async (value) => {
|
||||||
if (value && value.indexOf("/") === 0) {
|
if (value && value.indexOf("/") === 0) {
|
||||||
try {
|
try {
|
||||||
const { data } = await api.get("/quickAnswers/", {
|
const { data } = await api.get("/quickAnswers/", {
|
||||||
params: { searchParam: inputMessage.substring(1) },
|
params: { searchParam: inputMessage.substring(1) },
|
||||||
})
|
});
|
||||||
setQuickAnswer(data.quickAnswers)
|
setQuickAnswer(data.quickAnswers);
|
||||||
if (data.quickAnswers.length > 0) {
|
if (data.quickAnswers.length > 0) {
|
||||||
setTypeBar(true)
|
setTypeBar(true);
|
||||||
} else {
|
} else {
|
||||||
setTypeBar(false)
|
setTypeBar(false);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setTypeBar(false)
|
setTypeBar(false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setTypeBar(false)
|
setTypeBar(false);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleUploadAudio = async () => {
|
const handleUploadAudio = async () => {
|
||||||
setLoading(true)
|
setLoading(true);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -463,45 +376,44 @@ const MessageInput = ({ ticketStatus }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const [, blob] = await Mp3Recorder.stop().getMp3()
|
const [, blob] = await Mp3Recorder.stop().getMp3();
|
||||||
if (blob.size < 10000) {
|
if (blob.size < 10000) {
|
||||||
setLoading(false)
|
setLoading(false);
|
||||||
setRecording(false)
|
setRecording(false);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const formData = new FormData()
|
const formData = new FormData();
|
||||||
const filename = `${new Date().getTime()}.mp3`
|
const filename = `${new Date().getTime()}.mp3`;
|
||||||
formData.append("medias", blob, filename)
|
formData.append("medias", blob, filename);
|
||||||
formData.append("body", filename)
|
formData.append("body", filename);
|
||||||
formData.append("fromMe", true)
|
formData.append("fromMe", true);
|
||||||
formData.append("mic_audio", true)
|
|
||||||
|
|
||||||
await api.post(`/messages/${ticketId}`, formData)
|
await api.post(`/messages/${ticketId}`, formData);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
toastError(err)
|
toastError(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
setRecording(false)
|
setRecording(false);
|
||||||
setLoading(false)
|
setLoading(false);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleCancelAudio = async () => {
|
const handleCancelAudio = async () => {
|
||||||
try {
|
try {
|
||||||
await Mp3Recorder.stop().getMp3()
|
await Mp3Recorder.stop().getMp3();
|
||||||
setRecording(false)
|
setRecording(false);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
toastError(err)
|
toastError(err);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleOpenMenuClick = (event) => {
|
const handleOpenMenuClick = (event) => {
|
||||||
setAnchorEl(event.currentTarget)
|
setAnchorEl(event.currentTarget);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleMenuItemClick = (event) => {
|
const handleMenuItemClick = (event) => {
|
||||||
setAnchorEl(null)
|
setAnchorEl(null);
|
||||||
}
|
};
|
||||||
|
|
||||||
const renderReplyingMessage = (message) => {
|
const renderReplyingMessage = (message) => {
|
||||||
return (
|
return (
|
||||||
|
@ -530,8 +442,8 @@ const MessageInput = ({ ticketStatus }) => {
|
||||||
<ClearIcon className={classes.sendMessageIcons} />
|
<ClearIcon className={classes.sendMessageIcons} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
if (medias.length > 0)
|
if (medias.length > 0)
|
||||||
return (
|
return (
|
||||||
|
@ -563,7 +475,7 @@ const MessageInput = ({ ticketStatus }) => {
|
||||||
<SendIcon className={classes.sendMessageIcons} />
|
<SendIcon className={classes.sendMessageIcons} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Paper>
|
</Paper>
|
||||||
)
|
);
|
||||||
else {
|
else {
|
||||||
return (
|
return (
|
||||||
<Paper square elevation={0} className={classes.mainWrapper}>
|
<Paper square elevation={0} className={classes.mainWrapper}>
|
||||||
|
@ -617,7 +529,7 @@ const MessageInput = ({ ticketStatus }) => {
|
||||||
size="small"
|
size="small"
|
||||||
checked={signMessage}
|
checked={signMessage}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setSignMessage(e.target.checked)
|
setSignMessage(e.target.checked);
|
||||||
}}
|
}}
|
||||||
name="showAllTickets"
|
name="showAllTickets"
|
||||||
color="primary"
|
color="primary"
|
||||||
|
@ -679,7 +591,7 @@ const MessageInput = ({ ticketStatus }) => {
|
||||||
size="small"
|
size="small"
|
||||||
checked={signMessage}
|
checked={signMessage}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setSignMessage(e.target.checked)
|
setSignMessage(e.target.checked);
|
||||||
}}
|
}}
|
||||||
name="showAllTickets"
|
name="showAllTickets"
|
||||||
color="primary"
|
color="primary"
|
||||||
|
@ -692,8 +604,8 @@ const MessageInput = ({ ticketStatus }) => {
|
||||||
<div className={classes.messageInputWrapper}>
|
<div className={classes.messageInputWrapper}>
|
||||||
<InputBase
|
<InputBase
|
||||||
inputRef={(input) => {
|
inputRef={(input) => {
|
||||||
input && input.focus()
|
input && input.focus();
|
||||||
input && (inputRef.current = input)
|
input && (inputRef.current = input);
|
||||||
}}
|
}}
|
||||||
className={classes.messageInput}
|
className={classes.messageInput}
|
||||||
placeholder={
|
placeholder={
|
||||||
|
@ -708,12 +620,12 @@ const MessageInput = ({ ticketStatus }) => {
|
||||||
onChange={handleChangeInput}
|
onChange={handleChangeInput}
|
||||||
disabled={recording || loading || ticketStatus !== "open"}
|
disabled={recording || loading || ticketStatus !== "open"}
|
||||||
onPaste={(e) => {
|
onPaste={(e) => {
|
||||||
ticketStatus === "open" && handleInputPaste(e)
|
ticketStatus === "open" && handleInputPaste(e);
|
||||||
}}
|
}}
|
||||||
onKeyPress={(e) => {
|
onKeyPress={(e) => {
|
||||||
if (loading || e.shiftKey) return
|
if (loading || e.shiftKey) return;
|
||||||
else if (e.key === "Enter") {
|
else if (e.key === "Enter") {
|
||||||
handleSendMessage()
|
handleSendMessage();
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
@ -730,7 +642,7 @@ const MessageInput = ({ ticketStatus }) => {
|
||||||
{`${value.shortcut} - ${value.message}`}
|
{`${value.shortcut} - ${value.message}`}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
)
|
);
|
||||||
})}
|
})}
|
||||||
</ul>
|
</ul>
|
||||||
) : (
|
) : (
|
||||||
|
@ -786,8 +698,8 @@ const MessageInput = ({ ticketStatus }) => {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Paper>
|
</Paper>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
export default MessageInput
|
export default MessageInput;
|
||||||
|
|
|
@ -56,7 +56,7 @@ const MessageOptionsMenu = ({ message, menuOpen, handleClose, anchorEl }) => {
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
>
|
>
|
||||||
{message.fromMe && (
|
{message.fromMe && (
|
||||||
<MenuItem onClick={handleOpenConfirmationModal} disabled={message?.phoneNumberId ? true : false}>
|
<MenuItem onClick={handleOpenConfirmationModal}>
|
||||||
{i18n.t("messageOptionsMenu.delete")}
|
{i18n.t("messageOptionsMenu.delete")}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -1,242 +0,0 @@
|
||||||
|
|
||||||
import React, { useState, useEffect, useRef, } from 'react'
|
|
||||||
import Button from '@mui/material/Button'
|
|
||||||
import Dialog from '@mui/material/Dialog'
|
|
||||||
import DialogActions from '@mui/material/DialogActions'
|
|
||||||
import DialogContent from '@mui/material/DialogContent'
|
|
||||||
import DialogContentText from '@mui/material/DialogContentText'
|
|
||||||
import DialogTitle from '@mui/material/DialogTitle'
|
|
||||||
import SelectField from "../Report/SelectField"
|
|
||||||
|
|
||||||
import TextField from '@mui/material/TextField'
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const ModalTemplate = ({ templates, modal_header, func }) => {
|
|
||||||
|
|
||||||
templates = [{}, ...templates]
|
|
||||||
|
|
||||||
const [open, setOpen] = useState(true)
|
|
||||||
const [scroll, /*setScroll*/] = useState('body')
|
|
||||||
const [templateId, setTemplateId] = useState(null)
|
|
||||||
const [templateComponents, setTemplateComponents] = useState(null)
|
|
||||||
const [language, setLanguage] = useState(null)
|
|
||||||
const [params, setParams] = useState([])
|
|
||||||
|
|
||||||
const handleCancel = (event, reason) => {
|
|
||||||
|
|
||||||
if (reason && reason === "backdropClick")
|
|
||||||
return
|
|
||||||
|
|
||||||
setOpen(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleChatEnd = () => {
|
|
||||||
|
|
||||||
console.log('PARAMS TO SEND TO MESSAGE INPUT: ', params)
|
|
||||||
func(params)
|
|
||||||
setOpen(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
const descriptionElementRef = useRef(null)
|
|
||||||
useEffect(() => {
|
|
||||||
if (open) {
|
|
||||||
const { current: descriptionElement } = descriptionElementRef
|
|
||||||
if (descriptionElement !== null) {
|
|
||||||
descriptionElement.focus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [open])
|
|
||||||
|
|
||||||
|
|
||||||
// Get from child 1
|
|
||||||
const changedTextFieldSelect = (data) => {
|
|
||||||
setTemplateId(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
|
|
||||||
const index = templates.findIndex(t => t.id === templateId)
|
|
||||||
setParams([])
|
|
||||||
if (index !== -1) {
|
|
||||||
|
|
||||||
const { components, language, name } = templates[index]
|
|
||||||
|
|
||||||
setParams((params) => [...params, { 'template_name': name }])
|
|
||||||
|
|
||||||
const buttons = components.find(c => c.type === 'BUTTONS')
|
|
||||||
|
|
||||||
if (buttons) {
|
|
||||||
handleButtons(buttons?.buttons)
|
|
||||||
}
|
|
||||||
|
|
||||||
setTemplateComponents(components)
|
|
||||||
setLanguage(language)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setTemplateComponents(null)
|
|
||||||
setLanguage(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
}, [templateId])
|
|
||||||
|
|
||||||
const handleButtons = (buttons) => {
|
|
||||||
|
|
||||||
let buttonsParams = {
|
|
||||||
type: 'BUTTONS',
|
|
||||||
parameters: []
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buttons && buttons.length > 0) {
|
|
||||||
for (let i in buttons) {
|
|
||||||
const { text, type: sub_type } = buttons[i]
|
|
||||||
buttonsParams.parameters.push({ sub_type, text, index: i, })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setParams((params) => [...params, buttonsParams])
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleTextChange = (value, index, type, text, language,) => {
|
|
||||||
|
|
||||||
if (!params) return
|
|
||||||
|
|
||||||
setParams((params) => {
|
|
||||||
|
|
||||||
const _index = params.findIndex(({ type }) => type === 'BODY')
|
|
||||||
|
|
||||||
if (_index !== -1) {
|
|
||||||
|
|
||||||
const indexParameter = params[_index].parameters.findIndex((param) => param.index === index)
|
|
||||||
|
|
||||||
if (indexParameter !== -1) {
|
|
||||||
params[_index].parameters[indexParameter] = { ...params[_index].parameters[indexParameter], type: 'text', text: value, index }
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
params[_index].parameters = [...params[_index].parameters, { type: 'text', text: value, index }]
|
|
||||||
}
|
|
||||||
|
|
||||||
return params
|
|
||||||
|
|
||||||
}
|
|
||||||
return [...params, { type, text, language, parameters: [{ type: 'text', text: value, index }] }]
|
|
||||||
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
console.log('---------> PARAMS: ', params)
|
|
||||||
}, [params])
|
|
||||||
|
|
||||||
const dinamicTextField = (replicateItems, func, type, text, language) => {
|
|
||||||
|
|
||||||
let textFields = Array.from({ length: replicateItems }, (_, index) => index)
|
|
||||||
|
|
||||||
return textFields.map((t) => {
|
|
||||||
return <TextField
|
|
||||||
key={t}
|
|
||||||
label={`{{${t + 1}}}`}
|
|
||||||
variant="outlined"
|
|
||||||
style={{ margin: '4px', }} // Adjust the height as needed
|
|
||||||
onChange={(e) => func(e.target.value, (t + 1), type, text, language)}
|
|
||||||
/>
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
|
||||||
|
|
||||||
<Dialog
|
|
||||||
open={open}
|
|
||||||
onClose={handleCancel}
|
|
||||||
// fullWidth={true}
|
|
||||||
// maxWidth={true}
|
|
||||||
disableEscapeKeyDown
|
|
||||||
|
|
||||||
scroll={scroll}
|
|
||||||
aria-labelledby="scroll-dialog-title"
|
|
||||||
aria-describedby="scroll-dialog-description"
|
|
||||||
>
|
|
||||||
|
|
||||||
<DialogTitle id="scroll-dialog-title">{modal_header}</DialogTitle>
|
|
||||||
<DialogContent dividers={scroll === 'body'}>
|
|
||||||
|
|
||||||
<DialogContentText
|
|
||||||
id="scroll-dialog-description"
|
|
||||||
ref={descriptionElementRef}
|
|
||||||
tabIndex={-1}
|
|
||||||
>
|
|
||||||
|
|
||||||
</DialogContentText>
|
|
||||||
|
|
||||||
<>
|
|
||||||
|
|
||||||
<SelectField func={changedTextFieldSelect}
|
|
||||||
emptyField={false}
|
|
||||||
textBoxFieldSelected={'1'}
|
|
||||||
header={'Selecione um template'}
|
|
||||||
currencies={templates.map((template,) => {
|
|
||||||
const { name, id } = template
|
|
||||||
return { 'value': id, 'label': name }
|
|
||||||
})} />
|
|
||||||
|
|
||||||
{templateComponents &&
|
|
||||||
templateComponents.map((components,) => {
|
|
||||||
const { type, format, text, buttons } = components
|
|
||||||
|
|
||||||
let body_params = 0
|
|
||||||
|
|
||||||
if (type === 'BODY') {
|
|
||||||
body_params = text.match(/{{\d+}}/g)
|
|
||||||
}
|
|
||||||
|
|
||||||
const titleCss = {
|
|
||||||
margin: 0,
|
|
||||||
fontSize: 12
|
|
||||||
}
|
|
||||||
const valueCss = { margin: 0, padding: 0, 'marginBottom': '15px', fontSize: 12 }
|
|
||||||
const valueCssButton = { margin: 0, padding: 0, fontSize: 11 }
|
|
||||||
|
|
||||||
return <div key={text}>
|
|
||||||
{type && <strong style={titleCss}>{type}</strong>}
|
|
||||||
{format && format !== 'TEXT' && <p style={valueCss}>TYPE {format}</p>}
|
|
||||||
{text &&
|
|
||||||
<div style={{ margin: 0, padding: 0, 'marginBottom': '15px' }}>
|
|
||||||
<p style={{ margin: 0, padding: 0, fontSize: 12 }}>{text}</p>
|
|
||||||
{type && (type === 'BODY') && dinamicTextField(body_params.length, handleTextChange, type, text, language)}
|
|
||||||
</div>}
|
|
||||||
{buttons && <div>{buttons.map((b) => {
|
|
||||||
const { type, text, url } = b
|
|
||||||
return <div style={{ margin: 0, padding: 0, 'marginBottom': '10px' }}>
|
|
||||||
{type && <p style={valueCssButton}>TYPE {type}</p>}
|
|
||||||
{text && <p style={valueCssButton}>{text}</p>}
|
|
||||||
{url && <p style={valueCssButton}>{url}</p>}
|
|
||||||
</div>
|
|
||||||
})} </div>}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</DialogContent>
|
|
||||||
|
|
||||||
|
|
||||||
<DialogActions>
|
|
||||||
<div style={{ marginRight: '50px' }}>
|
|
||||||
<Button onClick={handleCancel}>Cancelar</Button>
|
|
||||||
</div>
|
|
||||||
<Button onClick={handleChatEnd}>Ok</Button>
|
|
||||||
</DialogActions>
|
|
||||||
</Dialog >
|
|
||||||
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ModalTemplate
|
|
|
@ -87,15 +87,8 @@ const NewTicketModal = ({ modalOpen, onClose }) => {
|
||||||
if (newValue?.number) {
|
if (newValue?.number) {
|
||||||
setSelectedContact(newValue);
|
setSelectedContact(newValue);
|
||||||
} else if (newValue?.name) {
|
} else if (newValue?.name) {
|
||||||
|
setNewContact({ name: newValue.name });
|
||||||
if (/^-?\d+(\.\d+)?$/.test(newValue?.name)) {
|
setContactModalOpen(true);
|
||||||
setNewContact({ number: newValue.name })
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setNewContact({ name: newValue.name })
|
|
||||||
}
|
|
||||||
|
|
||||||
setContactModalOpen(true)
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
import React, { useState, useRef, useEffect, useContext } from "react"
|
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 useSound from "use-sound"
|
import useSound from "use-sound";
|
||||||
|
|
||||||
import Popover from "@material-ui/core/Popover"
|
import Popover from "@material-ui/core/Popover";
|
||||||
//import IconButton from "@material-ui/core/IconButton";
|
//import IconButton from "@material-ui/core/IconButton";
|
||||||
import List from "@material-ui/core/List"
|
import List from "@material-ui/core/List";
|
||||||
import ListItem from "@material-ui/core/ListItem"
|
import ListItem from "@material-ui/core/ListItem";
|
||||||
import ListItemText from "@material-ui/core/ListItemText"
|
import ListItemText from "@material-ui/core/ListItemText";
|
||||||
import { makeStyles } from "@material-ui/core/styles"
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
//import Badge from "@material-ui/core/Badge";
|
//import Badge from "@material-ui/core/Badge";
|
||||||
//import ChatIcon from "@material-ui/icons/Chat";
|
//import ChatIcon from "@material-ui/icons/Chat";
|
||||||
|
|
||||||
import TicketListItem from "../TicketListItem"
|
import TicketListItem from "../TicketListItem";
|
||||||
import { i18n } from "../../translate/i18n"
|
import { i18n } from "../../translate/i18n";
|
||||||
import useTickets from "../../hooks/useTickets"
|
import useTickets from "../../hooks/useTickets";
|
||||||
import alertSound from "../../assets/sound.mp3"
|
import alertSound from "../../assets/sound.mp3";
|
||||||
import { AuthContext } from "../../context/Auth/AuthContext"
|
import { AuthContext } from "../../context/Auth/AuthContext";
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => ({
|
const useStyles = makeStyles(theme => ({
|
||||||
tabContainer: {
|
tabContainer: {
|
||||||
|
@ -38,62 +38,89 @@ const useStyles = makeStyles(theme => ({
|
||||||
noShadow: {
|
noShadow: {
|
||||||
boxShadow: "none !important",
|
boxShadow: "none !important",
|
||||||
},
|
},
|
||||||
}))
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
let _fifo
|
||||||
|
|
||||||
|
// const onlineEmitter = async (socket, user) => {
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// clearInterval(_fifo);
|
||||||
|
|
||||||
|
// socket.emit("online", user.id)
|
||||||
|
|
||||||
|
// } catch (error) {
|
||||||
|
// console.log('error on onlineEmitter: ', error)
|
||||||
|
// }
|
||||||
|
// finally {
|
||||||
|
// _fifo = setInterval(onlineEmitter, 3000);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// _fifo = setInterval(onlineEmitter, 3000);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const NotificationsPopOver = () => {
|
const NotificationsPopOver = () => {
|
||||||
const classes = useStyles()
|
const classes = useStyles();
|
||||||
|
|
||||||
const history = useHistory()
|
const history = useHistory();
|
||||||
const { user } = useContext(AuthContext)
|
const { user } = useContext(AuthContext);
|
||||||
const ticketIdUrl = +history.location.pathname.split("/")[2]
|
const ticketIdUrl = +history.location.pathname.split("/")[2];
|
||||||
const ticketIdRef = useRef(ticketIdUrl)
|
const ticketIdRef = useRef(ticketIdUrl);
|
||||||
const anchorEl = useRef()
|
const anchorEl = useRef();
|
||||||
const [isOpen, setIsOpen] = useState(false)
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const [notifications, setNotifications] = useState([])
|
const [notifications, setNotifications] = useState([]);
|
||||||
|
|
||||||
const [, setDesktopNotifications] = useState([])
|
const [, setDesktopNotifications] = useState([]);
|
||||||
|
|
||||||
const { tickets } = useTickets({ withUnreadMessages: "true" })
|
const { tickets } = useTickets({ withUnreadMessages: "true" });
|
||||||
const [play] = useSound(alertSound)
|
const [play] = useSound(alertSound);
|
||||||
const soundAlertRef = useRef()
|
const soundAlertRef = useRef();
|
||||||
|
|
||||||
const historyRef = useRef(history)
|
const historyRef = useRef(history);
|
||||||
|
|
||||||
const { handleLogout } = useContext(AuthContext)
|
const { handleLogout } = useContext(AuthContext);
|
||||||
|
|
||||||
// const [lastRef] = useState(+history.location.pathname.split("/")[2])
|
// const [lastRef] = useState(+history.location.pathname.split("/")[2])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
soundAlertRef.current = play
|
soundAlertRef.current = play;
|
||||||
|
|
||||||
if (!("Notification" in window)) {
|
if (!("Notification" in window)) {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Notification.requestPermission()
|
Notification.requestPermission();
|
||||||
}
|
}
|
||||||
}, [play])
|
}, [play]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setNotifications(tickets)
|
setNotifications(tickets);
|
||||||
}, [tickets])
|
}, [tickets]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
ticketIdRef.current = ticketIdUrl
|
|
||||||
}, [ticketIdUrl])
|
|
||||||
|
|
||||||
|
ticketIdRef.current = ticketIdUrl;
|
||||||
|
}, [ticketIdUrl]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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) => {
|
||||||
|
|
||||||
if (user.id === data.userId) {
|
if (user.id === data.userId) {
|
||||||
|
|
||||||
window.location.reload(true)
|
window.location.reload(true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,15 +130,18 @@ const NotificationsPopOver = () => {
|
||||||
|
|
||||||
if (data.action === "logout") {
|
if (data.action === "logout") {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (`${user.id}` === data.userOnlineTime['userId']) {
|
if (`${user.id}` === data.userOnlineTime['userId']) {
|
||||||
|
|
||||||
socket.emit("online", { logoutUserId: user.id })
|
socket.emit("online", { logoutUserId: user.id })
|
||||||
handleLogout()
|
handleLogout();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
|
||||||
|
});
|
||||||
|
|
||||||
// socket.on("isOnline", (data) => {
|
// socket.on("isOnline", (data) => {
|
||||||
|
|
||||||
|
@ -129,145 +159,159 @@ const NotificationsPopOver = () => {
|
||||||
|
|
||||||
if (user.profile === 'user') {
|
if (user.profile === 'user') {
|
||||||
|
|
||||||
// if (_fifo) {
|
if (_fifo) {
|
||||||
// clearInterval(_fifo);
|
clearInterval(_fifo);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// _fifo = setInterval(() => {
|
_fifo = setInterval(() => {
|
||||||
// socket.emit("online", user.id)
|
|
||||||
// }, 3000);
|
|
||||||
|
|
||||||
const intID = setInterval(() => {
|
|
||||||
console.log('emitting the online')
|
|
||||||
socket.emit("online", user.id)
|
socket.emit("online", user.id)
|
||||||
}, 3000)
|
}, 3000);
|
||||||
|
|
||||||
return () => clearInterval(intID)
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
socket.disconnect()
|
socket.disconnect();
|
||||||
}
|
};
|
||||||
}, [user.id, handleLogout, user.profile])
|
}, [user.id, handleLogout, user.profile]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
|
const socket = openSocket(process.env.REACT_APP_BACKEND_URL);
|
||||||
|
|
||||||
socket.on("connect", () => socket.emit("joinNotification"))
|
socket.on("connect", () => socket.emit("joinNotification"));
|
||||||
|
|
||||||
|
|
||||||
socket.on("ticket", data => {
|
socket.on("ticket", data => {
|
||||||
if (data.action === "updateUnread" || data.action === "delete") {
|
if (data.action === "updateUnread" || data.action === "delete") {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
setNotifications(prevState => {
|
setNotifications(prevState => {
|
||||||
const ticketIndex = prevState.findIndex(t => t.id === data.ticketId)
|
const ticketIndex = prevState.findIndex(t => t.id === data.ticketId);
|
||||||
if (ticketIndex !== -1) {
|
if (ticketIndex !== -1) {
|
||||||
prevState.splice(ticketIndex, 1)
|
prevState.splice(ticketIndex, 1);
|
||||||
return [...prevState]
|
return [...prevState];
|
||||||
}
|
}
|
||||||
return prevState
|
return prevState;
|
||||||
})
|
});
|
||||||
|
|
||||||
setDesktopNotifications(prevState => {
|
setDesktopNotifications(prevState => {
|
||||||
const notfiticationIndex = prevState.findIndex(
|
const notfiticationIndex = prevState.findIndex(
|
||||||
n => n.tag === String(data.ticketId)
|
n => n.tag === String(data.ticketId)
|
||||||
)
|
);
|
||||||
if (notfiticationIndex !== -1) {
|
if (notfiticationIndex !== -1) {
|
||||||
prevState[notfiticationIndex].close()
|
prevState[notfiticationIndex].close();
|
||||||
prevState.splice(notfiticationIndex, 1)
|
prevState.splice(notfiticationIndex, 1);
|
||||||
return [...prevState]
|
return [...prevState];
|
||||||
}
|
}
|
||||||
return prevState
|
return prevState;
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
socket.on("appMessage", data => {
|
socket.on("appMessage", 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 => {
|
||||||
|
|
||||||
const ticketIndex = prevState.findIndex(t => t.id === data.ticket.id)
|
|
||||||
|
|
||||||
|
// prevState.forEach((e)=>{
|
||||||
|
//
|
||||||
|
// })
|
||||||
|
|
||||||
|
const ticketIndex = prevState.findIndex(t => t.id === data.ticket.id);
|
||||||
if (ticketIndex !== -1) {
|
if (ticketIndex !== -1) {
|
||||||
|
|
||||||
prevState[ticketIndex] = data.ticket
|
prevState[ticketIndex] = data.ticket;
|
||||||
return [...prevState]
|
return [...prevState];
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
if (shouldNotNotificate) return
|
if (shouldNotNotificate) return;
|
||||||
|
|
||||||
handleNotifications(data)
|
|
||||||
|
|
||||||
|
handleNotifications(data);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
socket.disconnect()
|
socket.disconnect();
|
||||||
}
|
};
|
||||||
}, [user])
|
}, [user]);
|
||||||
|
|
||||||
const handleNotifications = data => {
|
const handleNotifications = data => {
|
||||||
const { message, contact, ticket } = data
|
const { message, contact, ticket } = data;
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
body: `${message.body} - ${format(new Date(), "HH:mm")}`,
|
body: `${message.body} - ${format(new Date(), "HH:mm")}`,
|
||||||
icon: contact.profilePicUrl,
|
icon: contact.profilePicUrl,
|
||||||
tag: ticket.id,
|
tag: ticket.id,
|
||||||
renotify: true,
|
renotify: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
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}`);
|
||||||
}
|
};
|
||||||
|
|
||||||
setDesktopNotifications(prevState => {
|
setDesktopNotifications(prevState => {
|
||||||
const notfiticationIndex = prevState.findIndex(
|
const notfiticationIndex = prevState.findIndex(
|
||||||
n => n.tag === notification.tag
|
n => n.tag === notification.tag
|
||||||
)
|
);
|
||||||
if (notfiticationIndex !== -1) {
|
if (notfiticationIndex !== -1) {
|
||||||
prevState[notfiticationIndex] = notification
|
prevState[notfiticationIndex] = notification;
|
||||||
return [...prevState]
|
return [...prevState];
|
||||||
}
|
}
|
||||||
return [notification, ...prevState]
|
return [notification, ...prevState];
|
||||||
})
|
});
|
||||||
|
|
||||||
soundAlertRef.current()
|
soundAlertRef.current();
|
||||||
}
|
};
|
||||||
|
|
||||||
// const handleClick = () => {
|
// const handleClick = () => {
|
||||||
// setIsOpen(prevState => !prevState);
|
// setIsOpen(prevState => !prevState);
|
||||||
// };
|
// };
|
||||||
|
|
||||||
const handleClickAway = () => {
|
const handleClickAway = () => {
|
||||||
setIsOpen(false)
|
setIsOpen(false);
|
||||||
}
|
};
|
||||||
|
|
||||||
const NotificationTicket = ({ children }) => {
|
const NotificationTicket = ({ children }) => {
|
||||||
return <div onClick={handleClickAway}>{children}</div>
|
return <div onClick={handleClickAway}>{children}</div>;
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -315,7 +359,7 @@ const NotificationsPopOver = () => {
|
||||||
|
|
||||||
</Popover>
|
</Popover>
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default NotificationsPopOver
|
export default NotificationsPopOver;
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue