estado funcional whatsapp api oficial
parent
42535f2e6c
commit
6d525e4224
|
@ -16,6 +16,7 @@
|
||||||
"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",
|
||||||
|
@ -28,6 +29,7 @@
|
||||||
"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",
|
||||||
|
@ -42,6 +44,7 @@
|
||||||
"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",
|
||||||
|
|
|
@ -21,7 +21,8 @@ app.use(
|
||||||
credentials: true,
|
credentials: true,
|
||||||
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());
|
||||||
|
|
|
@ -17,6 +17,8 @@ import {
|
||||||
verifyMessage
|
verifyMessage
|
||||||
} from "../services/WbotServices/wbotMessageListener";
|
} from "../services/WbotServices/wbotMessageListener";
|
||||||
import CreateOrUpdateContactService from "../services/ContactServices/CreateOrUpdateContactService";
|
import CreateOrUpdateContactService from "../services/ContactServices/CreateOrUpdateContactService";
|
||||||
|
import sendWhatsAppMessageOfficialAPI from "../helpers/sendWhatsAppMessageOfficialAPI";
|
||||||
|
import Whatsapp from "../models/Whatsapp";
|
||||||
|
|
||||||
type IndexQuery = {
|
type IndexQuery = {
|
||||||
pageNumber: string;
|
pageNumber: string;
|
||||||
|
@ -27,6 +29,7 @@ type MessageData = {
|
||||||
fromMe: boolean;
|
fromMe: boolean;
|
||||||
read: boolean;
|
read: boolean;
|
||||||
quotedMsg?: Message;
|
quotedMsg?: Message;
|
||||||
|
mic_audio?: boolean
|
||||||
};
|
};
|
||||||
|
|
||||||
export const index = async (req: Request, res: Response): Promise<Response> => {
|
export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||||
|
@ -37,104 +40,19 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||||
pageNumber,
|
pageNumber,
|
||||||
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 }: MessageData = req.body;
|
const { body, quotedMsg, mic_audio }: 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;
|
const { queueId } = ticket;
|
||||||
console.log("-----------> queueId: ", queueId);
|
console.log("-----------> queueId: ", queueId, " | quotedMsg: ", quotedMsg);
|
||||||
|
|
||||||
// TEST FILA DE ATENDIMENTO 42 WHATSAPP OFFICIAL
|
|
||||||
if (queueId == 42) {
|
|
||||||
const { contactId } = ticket;
|
|
||||||
|
|
||||||
const contact: any = await Contact.findByPk(contactId);
|
|
||||||
|
|
||||||
const { number } = contact;
|
|
||||||
|
|
||||||
console.log("NUMBER: ", number);
|
|
||||||
console.log("CONTACT ID: ", contactId);
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
messaging_product: "whatsapp",
|
|
||||||
recipient_type: "individual",
|
|
||||||
to: number,
|
|
||||||
type: "text",
|
|
||||||
text: {
|
|
||||||
preview_url: true,
|
|
||||||
body
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!isValidMsg({ type: data.type })) {
|
|
||||||
return res.status(400).json({ message: "Wrong message type" });
|
|
||||||
}
|
|
||||||
|
|
||||||
whatsappOfficialAPI
|
|
||||||
.post("/v17.0/105394365522185/messagess", data)
|
|
||||||
.then(response => {
|
|
||||||
console.log("Response:", response.data);
|
|
||||||
|
|
||||||
if (response.status == 200) {
|
|
||||||
console.log("STATUS 200");
|
|
||||||
}
|
|
||||||
|
|
||||||
let msg = {};
|
|
||||||
|
|
||||||
msg = {
|
|
||||||
...msg,
|
|
||||||
id: { id: response.data.messages[0].id },
|
|
||||||
fromMe: true,
|
|
||||||
type: "chat",
|
|
||||||
read: false,
|
|
||||||
body
|
|
||||||
};
|
|
||||||
|
|
||||||
verifyMessage(msg, ticket, contact, quotedMsg);
|
|
||||||
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.log(
|
|
||||||
"Error on try request: ",
|
|
||||||
error.response.data.error.message
|
|
||||||
);
|
|
||||||
|
|
||||||
// return res
|
|
||||||
// .status(500)
|
|
||||||
// .json({ error: error.response.data.error.message });
|
|
||||||
|
|
||||||
if (error?.response?.data?.error?.message && error.response?.status) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error.response) {
|
|
||||||
// The request was made and the server responded with a non-2xx status code
|
|
||||||
throw new Error(
|
|
||||||
`Request failed with status ${error.response.status}`
|
|
||||||
);
|
|
||||||
} else if (error.request) {
|
|
||||||
// The request was made but no response was received (e.g., network error)
|
|
||||||
throw new Error("No response received from the server");
|
|
||||||
} else {
|
|
||||||
// Something happened in setting up the request that triggered an error
|
|
||||||
throw new Error("Request configuration error");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// return res.status(500).json({ error: "Internal server error" });
|
|
||||||
|
|
||||||
return res.send();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ORIGINAL
|
|
||||||
if (medias) {
|
if (medias) {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
medias.map(async (media: Express.Multer.File) => {
|
medias.map(async (media: Express.Multer.File) => {
|
||||||
|
@ -152,9 +70,8 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
media:`,
|
media:`,
|
||||||
media,
|
media,
|
||||||
"\n"
|
"\n"
|
||||||
);
|
);
|
||||||
|
await SendWhatsAppMedia({ media, ticket, mic_audio });
|
||||||
await SendWhatsAppMedia({ media, ticket });
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -103,7 +103,8 @@ 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 }: TicketData = req.body;
|
const { contactId, status, userId, msg, queueId, whatsappId }: TicketData =
|
||||||
|
req.body;
|
||||||
|
|
||||||
let ticket = await Ticket.findOne({
|
let ticket = await Ticket.findOne({
|
||||||
where: {
|
where: {
|
||||||
|
@ -120,7 +121,13 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
|
||||||
ticketId: ticket.id
|
ticketId: ticket.id
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
ticket = await CreateTicketService({ contactId, status, userId, queueId });
|
ticket = await CreateTicketService({
|
||||||
|
contactId,
|
||||||
|
status,
|
||||||
|
userId,
|
||||||
|
queueId,
|
||||||
|
whatsappId
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const io = getIO();
|
const io = getIO();
|
||||||
|
@ -128,15 +135,6 @@ 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);
|
||||||
};
|
};
|
||||||
|
@ -243,9 +241,9 @@ export const update = async (
|
||||||
|
|
||||||
if (getSettingValue("oneContactChatWithManyWhats")?.value == "enabled") {
|
if (getSettingValue("oneContactChatWithManyWhats")?.value == "enabled") {
|
||||||
if (ticketData.transfer) {
|
if (ticketData.transfer) {
|
||||||
const defaultWhatsapp: any = await GetDefaultWhatsApp(
|
const defaultWhatsapp: any = await GetDefaultWhatsApp({
|
||||||
ticketData.userId
|
userId: ticketData.userId
|
||||||
);
|
});
|
||||||
|
|
||||||
const _ticket: any = await Ticket.findByPk(ticketId);
|
const _ticket: any = await Ticket.findByPk(ticketId);
|
||||||
|
|
||||||
|
@ -276,8 +274,6 @@ 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 }))
|
||||||
|
|
|
@ -16,19 +16,25 @@ 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 from "path";
|
import path, { join } 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 Message from "../models/Message";
|
||||||
import FindOrCreateTicketService from "../services/TicketServices/FindOrCreateTicketService";
|
import FindOrCreateTicketService from "../services/TicketServices/FindOrCreateTicketService";
|
||||||
import {
|
import {
|
||||||
|
handleMessage,
|
||||||
handleMsgAck,
|
handleMsgAck,
|
||||||
verifyContact,
|
verifyContact,
|
||||||
verifyMessage
|
verifyMessage
|
||||||
} from "../services/WbotServices/wbotMessageListener";
|
} from "../services/WbotServices/wbotMessageListener";
|
||||||
import Contact from "../models/Contact";
|
import Contact from "../models/Contact";
|
||||||
import CreateOrUpdateContactService from "../services/ContactServices/CreateOrUpdateContactService";
|
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";
|
||||||
|
|
||||||
interface WhatsappData {
|
interface WhatsappData {
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -47,12 +53,113 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||||
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;
|
||||||
|
|
||||||
|
const whatsapps = await GetDefaultWhatsApp({ userId, queueId });
|
||||||
|
|
||||||
|
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 (
|
export const weebhook = async (
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response
|
res: Response
|
||||||
): Promise<Response> => {
|
): Promise<Response> => {
|
||||||
// console.log(JSON.stringify(req.body, null, 2));
|
// 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
|
// MESSAGE
|
||||||
if (req.body.object) {
|
if (req.body.object) {
|
||||||
if (
|
if (
|
||||||
|
@ -62,37 +169,71 @@ export const weebhook = async (
|
||||||
req.body.entry[0].changes[0].value.messages &&
|
req.body.entry[0].changes[0].value.messages &&
|
||||||
req.body.entry[0].changes[0].value.messages[0]
|
req.body.entry[0].changes[0].value.messages[0]
|
||||||
) {
|
) {
|
||||||
const contact_from = req.body.entry[0].changes[0].value.messages[0].from; // extract the phone number from the webhook payload
|
const message = req.body.entry[0].changes[0].value.messages[0];
|
||||||
const msg_body = req.body.entry[0].changes[0].value.messages[0].text.body; // extract the message text from the webhook payload
|
const contact_from = message.from; // extract the phone number from the webhook payload
|
||||||
const type = req.body.entry[0].changes[0].value.messages[0].type;
|
|
||||||
const contact_to =
|
const contact_to =
|
||||||
req.body.entry[0].changes[0].value.metadata.display_phone_number;
|
req.body.entry[0].changes[0].value.metadata.display_phone_number;
|
||||||
|
let type = message.type;
|
||||||
|
|
||||||
console.log("from: ", contact_from);
|
let wbot = {};
|
||||||
console.log("to: ", contact_to);
|
|
||||||
console.log("msg_body: ", msg_body);
|
|
||||||
console.log("msg type: ", type);
|
|
||||||
|
|
||||||
const contact: any = await verifyContact(null, { number: contact_from });
|
|
||||||
|
|
||||||
const whatsapp: any = await Whatsapp.findOne({
|
|
||||||
where: { number: contact_to }
|
|
||||||
});
|
|
||||||
|
|
||||||
const ticket = await FindOrCreateTicketService(contact, whatsapp.id, 1);
|
|
||||||
|
|
||||||
let msg = {};
|
let msg = {};
|
||||||
|
let contacts = req.body.entry[0].changes[0].value.contacts[0];
|
||||||
|
|
||||||
msg = {
|
msg = {
|
||||||
...msg,
|
...msg,
|
||||||
id: { id: req.body.entry[0].changes[0].value.messages[0].id },
|
id: { id: message.id },
|
||||||
fromMe: false,
|
fromMe: false,
|
||||||
type: type === "text" ? "chat" : type,
|
type: type,
|
||||||
read: false,
|
read: false,
|
||||||
body: req.body.entry[0].changes[0].value.messages[0].text.body
|
hasMedia: false
|
||||||
};
|
};
|
||||||
|
|
||||||
await verifyMessage(msg, ticket, contact, undefined);
|
// 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,
|
||||||
|
};
|
||||||
|
} 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 } };
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
return res.sendStatus(200);
|
||||||
}
|
}
|
||||||
|
@ -266,5 +407,3 @@ export const remove = async (
|
||||||
|
|
||||||
return res.status(200).json({ message: "Whatsapp deleted." });
|
return res.status(200).json({ message: "Whatsapp deleted." });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
};
|
|
@ -2,13 +2,13 @@ import { QueryInterface, DataTypes } from "sequelize";
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
up: (queryInterface: QueryInterface) => {
|
up: (queryInterface: QueryInterface) => {
|
||||||
return queryInterface.addColumn("Whatsapps", "official", {
|
return queryInterface.addColumn("Tickets", "phoneNumberId", {
|
||||||
type: DataTypes.BOOLEAN,
|
type: DataTypes.STRING,
|
||||||
defaultValue: false
|
allowNull: true
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
down: (queryInterface: QueryInterface) => {
|
down: (queryInterface: QueryInterface) => {
|
||||||
return queryInterface.removeColumn("Whatsapps", "official");
|
return queryInterface.removeColumn("Tickets", "phoneNumberId");
|
||||||
}
|
}
|
||||||
};
|
};
|
|
@ -0,0 +1,14 @@
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,3 @@
|
||||||
|
export function bytesToMB(bytes: number | string) {
|
||||||
|
return (+bytes / (1024 * 1024)).toFixed(2);
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
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,55 +1,66 @@
|
||||||
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 WhatsQueueIndex from "./WhatsQueueIndex";
|
||||||
|
|
||||||
import { WhatsIndex } from "./LoadBalanceWhatsSameQueue";
|
import { WhatsIndex } from "./LoadBalanceWhatsSameQueue";
|
||||||
|
|
||||||
const GetDefaultWhatsApp = async (userId?: string | number): Promise<Whatsapp> => {
|
interface Request {
|
||||||
|
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 });
|
||||||
|
|
||||||
let whatsapps = await wbotByUserQueue(userId)
|
if (userId && queueId) {
|
||||||
|
if (whatsapps.length > 1) {
|
||||||
|
let whatsAppOfficial: any = whatsapps.find(
|
||||||
|
(w: any) => w.phoneNumberId != null
|
||||||
|
);
|
||||||
|
|
||||||
if (whatsapps.length > 0) {
|
if (whatsAppOfficial) {
|
||||||
|
return whatsapps;
|
||||||
if (whatsapps.length > 1) {
|
}
|
||||||
|
|
||||||
defaultWhatsapp = whatsapps[+WhatsIndex(whatsapps)]
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
defaultWhatsapp = whatsapps[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
}// Quando o usuário não está em nenhuma fila
|
|
||||||
else {
|
|
||||||
defaultWhatsapp = await Whatsapp.findOne({ where: { status: 'CONNECTED' } });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (whatsapps.length > 0) {
|
||||||
|
if (whatsapps.length > 1) {
|
||||||
|
defaultWhatsapp = whatsapps[+WhatsIndex(whatsapps)];
|
||||||
|
} else {
|
||||||
|
defaultWhatsapp = whatsapps[0];
|
||||||
|
}
|
||||||
|
} // Quando o usuário não está em nenhuma fila
|
||||||
|
else {
|
||||||
|
defaultWhatsapp = await Whatsapp.findOne({
|
||||||
|
where: { status: "CONNECTED" }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
defaultWhatsapp = await Whatsapp.findOne({
|
||||||
|
where: { status: "CONNECTED" }
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
|
|
||||||
defaultWhatsapp = await Whatsapp.findOne({ where: { status: 'CONNECTED' } });
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!defaultWhatsapp) {
|
if (!defaultWhatsapp) {
|
||||||
|
@ -58,20 +69,6 @@ const GetDefaultWhatsApp = async (userId?: string | number): Promise<Whatsapp> =
|
||||||
|
|
||||||
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,50 +1,64 @@
|
||||||
|
|
||||||
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";
|
||||||
|
|
||||||
const wbotByUserQueue = async (userId: string | number, status: string = 'CONNECTED') => {
|
interface Request {
|
||||||
|
userId: string | number;
|
||||||
let defaultWhatsapp: Whatsapp[] = []
|
status?: string;
|
||||||
|
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;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default wbotByUserQueue;
|
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;
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
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,21 +1,33 @@
|
||||||
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 ) {
|
function sendWhatsAppMessageSocket(
|
||||||
|
ticket: Ticket,
|
||||||
|
body: string,
|
||||||
|
quotedMsgSerializedId?: string | undefined,
|
||||||
|
number?: string
|
||||||
|
) {
|
||||||
|
const { phoneNumberId } = ticket;
|
||||||
|
|
||||||
const io = getIO();
|
if (phoneNumberId) {
|
||||||
|
sendWhatsAppMessageOfficialAPI(ticket, body, quotedMsgSerializedId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
io.to(`session_${ticket.whatsappId.toString()}`).emit("send_message", {
|
const io = getIO();
|
||||||
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;
|
||||||
|
|
|
@ -1,12 +1,27 @@
|
||||||
|
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) {
|
||||||
const wbot_url = await getWbot(ticket.whatsappId);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
console.log('from wbotMessagelistener wbot_url: ', wbot_url, ' | ticket.contact.number: ', ticket.contact.number);
|
const wbot_url = await getWbot(ticket.whatsappId);
|
||||||
|
|
||||||
await endPointQuery(`${wbot_url}/api/sendSeen`, { number: `${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us` });
|
console.log(
|
||||||
}
|
"from wbotMessagelistener wbot_url: ",
|
||||||
|
wbot_url,
|
||||||
|
" | ticket.contact.number: ",
|
||||||
|
ticket.contact.number
|
||||||
|
);
|
||||||
|
|
||||||
|
await endPointQuery(`${wbot_url}/api/sendSeen`, {
|
||||||
|
number: `${ticket.contact.number}@${ticket.isGroup ? "g" : "c"}.us`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
const token =
|
|
||||||
"EAADwEiQkJqABOZBOuvnVZAywgKUw8wPETCcleXWDqKN3X2W1LZC5UMEnSjBIVjBavZBxwVTD4WnpDmoEFN9HZCOt842XZCTSPm1ShnnUB2iJca3nZC6gS8GLIKqP78kkW5EtllhWrg4I8JnbllrLNKa2B066Wwh0G3uySYgcA7WnKyZAmPOGEZB8UiljBaqhg";
|
|
||||||
|
|
||||||
const api = axios.create({
|
const api = axios.create({
|
||||||
baseURL: "https://graph.facebook.com",
|
baseURL: process.env.URL_WHATSAPP_API,
|
||||||
headers: {
|
headers: {
|
||||||
Accept: "application/json",
|
Accept: "application/json",
|
||||||
Authorization: `Bearer ${token}`
|
Authorization: `Bearer ${process.env.TOKEN}`
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
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
|
||||||
|
) {
|
||||||
|
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,
|
||||||
|
type: "text",
|
||||||
|
text: {
|
||||||
|
preview_url: true,
|
||||||
|
body
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (quotedMsgSerializedId) {
|
||||||
|
data = { ...data, context: { message_id: quotedMsgSerializedId.id } };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isValidMsg({ type: data.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 },
|
||||||
|
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;
|
|
@ -0,0 +1,106 @@
|
||||||
|
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;
|
|
@ -34,10 +34,15 @@ 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}:${process.env.PROXY_PORT}/public/${this.getDataValue("mediaUrl")}`;
|
return `${process.env.BACKEND_URL}:${
|
||||||
|
process.env.PROXY_PORT
|
||||||
|
}/public/${this.getDataValue("mediaUrl")}`;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,9 @@ class Ticket extends Model<Ticket> {
|
||||||
@Column
|
@Column
|
||||||
statusChatEnd: string;
|
statusChatEnd: string;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
phoneNumberId: string;
|
||||||
|
|
||||||
@CreatedAt
|
@CreatedAt
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
|
|
||||||
|
|
|
@ -58,10 +58,13 @@ class Whatsapp extends Model<Whatsapp> {
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
url: string;
|
url: string;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
urlApi: string;
|
urlApi: string;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
phoneNumberId: string;
|
||||||
|
|
||||||
@Default(false)
|
@Default(false)
|
||||||
@AllowNull
|
@AllowNull
|
||||||
@Column
|
@Column
|
||||||
|
|
|
@ -9,8 +9,22 @@ 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.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);
|
||||||
|
|
|
@ -43,13 +43,17 @@ gracefulShutdown(server);
|
||||||
|
|
||||||
loadSettings();
|
loadSettings();
|
||||||
|
|
||||||
let whatsapps: any = await Whatsapp.findAll({ attributes: ["id", "url"] });
|
let whatsapps: any = await Whatsapp.findAll({
|
||||||
|
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`
|
||||||
);
|
);
|
||||||
|
|
|
@ -23,6 +23,7 @@ const CreateMessageService = async ({
|
||||||
}: Request): Promise<Message> => {
|
}: Request): Promise<Message> => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
await Message.upsert(messageData);
|
await Message.upsert(messageData);
|
||||||
|
|
||||||
const message = await Message.findByPk(messageData.id, {
|
const message = await Message.findByPk(messageData.id, {
|
||||||
|
|
|
@ -15,6 +15,7 @@ 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";
|
||||||
let flatten = require("flat");
|
let flatten = require("flat");
|
||||||
|
|
||||||
interface Request {
|
interface Request {
|
||||||
|
@ -22,18 +23,29 @@ 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 {
|
||||||
const defaultWhatsapp = await GetDefaultWhatsApp(userId);
|
let defaultWhatsapp;
|
||||||
|
|
||||||
|
if (whatsappId) {
|
||||||
|
defaultWhatsapp = await Whatsapp.findByPk(whatsappId);
|
||||||
|
} else {
|
||||||
|
defaultWhatsapp = await GetDefaultWhatsApp({ userId, queueId });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 });
|
||||||
|
|
||||||
|
@ -56,7 +68,8 @@ 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,14 +13,14 @@ 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") {
|
// 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,7 +45,7 @@ const FindOrCreateTicketService = async (
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { queues, greetingMessage } = await ShowWhatsAppService(whatsappId);
|
const { queues, greetingMessage, phoneNumberId } = await ShowWhatsAppService(whatsappId);
|
||||||
|
|
||||||
const botInfo = { isOnQueue: false };
|
const botInfo = { isOnQueue: false };
|
||||||
|
|
||||||
|
@ -106,7 +106,8 @@ const FindOrCreateTicketService = async (
|
||||||
status: status,
|
status: status,
|
||||||
isGroup: !!groupContact,
|
isGroup: !!groupContact,
|
||||||
unreadMessages,
|
unreadMessages,
|
||||||
whatsappId
|
whatsappId,
|
||||||
|
phoneNumberId
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,8 +47,7 @@ const UpdateTicketService = async ({
|
||||||
whatsappId
|
whatsappId
|
||||||
} = ticketData;
|
} = ticketData;
|
||||||
|
|
||||||
const ticket = await ShowTicketService(ticketId);
|
const ticket = await ShowTicketService(ticketId);
|
||||||
// await SetTicketMessagesAsRead(ticket);
|
|
||||||
|
|
||||||
const oldStatus = ticket.status;
|
const oldStatus = ticket.status;
|
||||||
const oldUserId = ticket.user?.id;
|
const oldUserId = ticket.user?.id;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -4,19 +4,15 @@ 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,47 +4,61 @@ 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> => {
|
||||||
try {
|
const { phoneNumberId } = ticket;
|
||||||
// const wbot = await GetTicketWbot(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 {
|
||||||
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 });
|
||||||
|
|
||||||
// TEST DEL
|
await updateTicketCacheByTicketId(ticket.id, {
|
||||||
await updateTicketCacheByTicketId(ticket.id, { lastMessage: media.filename, updatedAt: new Date(ticket.updatedAt).toISOString() })
|
lastMessage: media.filename,
|
||||||
//
|
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,11 +8,14 @@ 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 { deleteTicketsByContactsCache, updateTicketCacheByTicketId } from '../../helpers/TicketCache'
|
import {
|
||||||
|
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";
|
||||||
|
@ -26,14 +29,13 @@ 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 ({
|
||||||
|
@ -42,112 +44,109 @@ const SendWhatsAppMessage = async ({
|
||||||
quotedMsg,
|
quotedMsg,
|
||||||
number
|
number
|
||||||
}: Request): Promise<WbotMessage | any> => {
|
}: Request): Promise<WbotMessage | any> => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const { phoneNumberId } = ticket;
|
||||||
|
|
||||||
// let timestamp = Math.floor(Date.now() / 1000)
|
if (phoneNumberId) {
|
||||||
let timestamp = Date.now() + String(Math.floor(Math.random() * 1000))
|
sendWhatsAppMessageOfficialAPI(ticket, body, quotedMsg);
|
||||||
|
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 whatsapps: any
|
let listWhatsapp = null;
|
||||||
|
|
||||||
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({
|
||||||
const defaultWhatsapp: any = await GetDefaultWhatsApp(ticket.userId);
|
userId: 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 (listWhatsapp.whatsapp && listWhatsapp.whatsapp.status != 'CONNECTED' && listWhatsapp.whatsapps.length > 0) {
|
if (
|
||||||
|
listWhatsapp.whatsapp &&
|
||||||
await ticket.update({ whatsappId: + listWhatsapp.whatsapps[0].id });
|
listWhatsapp.whatsapp.status != "CONNECTED" &&
|
||||||
|
listWhatsapp.whatsapps.length > 0
|
||||||
|
) {
|
||||||
|
await ticket.update({ whatsappId: +listWhatsapp.whatsapps[0].id });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (listWhatsapp.whatsapps.length > 1) {
|
if (listWhatsapp.whatsapps.length > 1) {
|
||||||
|
const _whatsapp =
|
||||||
const _whatsapp = listWhatsapp.whatsapps[Math.floor(Math.random() * listWhatsapp.whatsapps.length)];
|
listWhatsapp.whatsapps[
|
||||||
|
Math.floor(Math.random() * listWhatsapp.whatsapps.length)
|
||||||
|
];
|
||||||
|
|
||||||
await ticket.update({ whatsappId: +_whatsapp.id });
|
await ticket.update({ whatsappId: +_whatsapp.id });
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (listWhatsapp.whatsapps.length == 0 && listWhatsapp.whatsapp.status != 'CONNECTED') {
|
if (
|
||||||
|
listWhatsapp.whatsapps.length == 0 &&
|
||||||
|
listWhatsapp.whatsapp.status != "CONNECTED"
|
||||||
|
) {
|
||||||
|
console.log("listWhatsapp.whatsapps == 0");
|
||||||
|
|
||||||
console.log('listWhatsapp.whatsapps == 0')
|
whatsapps = await wbotByUserQueue({ userId: ticket.userId });
|
||||||
|
|
||||||
whatsapps = await wbotByUserQueue(ticket.userId)
|
console.log("============> The whatsapps: ", whatsapps);
|
||||||
|
|
||||||
console.log('============> The whatsapps: ', whatsapps)
|
|
||||||
|
|
||||||
if (whatsapps.length > 0) {
|
if (whatsapps.length > 0) {
|
||||||
|
|
||||||
if (whatsapps.length > 1) {
|
if (whatsapps.length > 1) {
|
||||||
|
await ticket.update({
|
||||||
await ticket.update({ whatsappId: whatsapps[+WhatsIndex(whatsapps)].id });
|
whatsappId: whatsapps[+WhatsIndex(whatsapps)].id
|
||||||
|
});
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
|
|
||||||
await ticket.update({ whatsappId: whatsapps[0].id });
|
await ticket.update({ whatsappId: whatsapps[0].id });
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('1 --------> send from whatsapp ticket.whatsappId: ', ticket.whatsappId)
|
console.log(
|
||||||
|
"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, { lastMessage: body, updatedAt: new Date(ticket.updatedAt).toISOString() })
|
await updateTicketCacheByTicketId(ticket.id, {
|
||||||
|
lastMessage: body,
|
||||||
console.timeEnd(timetaken)
|
updatedAt: new Date(ticket.updatedAt).toISOString()
|
||||||
|
});
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -110,7 +110,9 @@ const verifyContact = async (
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
contactData = {
|
contactData = {
|
||||||
name: whatsAppOfficial.number,
|
name: whatsAppOfficial?.name
|
||||||
|
? whatsAppOfficial.name
|
||||||
|
: whatsAppOfficial.number,
|
||||||
number: whatsAppOfficial.number,
|
number: whatsAppOfficial.number,
|
||||||
isGroup: false
|
isGroup: false
|
||||||
};
|
};
|
||||||
|
@ -151,22 +153,6 @@ const verifyMediaMessage = async (
|
||||||
throw new Error("ERR_WAPP_DOWNLOAD_MEDIA");
|
throw new Error("ERR_WAPP_DOWNLOAD_MEDIA");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!media.filename) {
|
|
||||||
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"
|
|
||||||
);
|
|
||||||
} catch (err) {
|
|
||||||
Sentry.captureException(err);
|
|
||||||
logger.error(`There was an error: wbotMessageLitener.ts: ${err}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const messageData = {
|
const messageData = {
|
||||||
id: msg.id.id,
|
id: msg.id.id,
|
||||||
ticketId: ticket.id,
|
ticketId: ticket.id,
|
||||||
|
@ -177,9 +163,26 @@ const verifyMediaMessage = async (
|
||||||
mediaUrl: media.filename,
|
mediaUrl: media.filename,
|
||||||
mediaType: media.mimetype.split("/")[0],
|
mediaType: media.mimetype.split("/")[0],
|
||||||
quotedMsgId: quotedMsg
|
quotedMsgId: quotedMsg
|
||||||
// quotedMsgId: quotedMsg?.id
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!ticket?.phoneNumberId) {
|
||||||
|
if (!media.filename) {
|
||||||
|
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"
|
||||||
|
);
|
||||||
|
} 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 });
|
||||||
|
|
||||||
|
@ -200,7 +203,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
|
||||||
};
|
};
|
||||||
|
|
||||||
await ticket.update({ lastMessage: msg.body });
|
await ticket.update({ lastMessage: msg.body });
|
||||||
|
@ -273,9 +277,6 @@ 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
|
||||||
|
@ -302,14 +303,13 @@ 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);
|
||||||
},
|
},
|
||||||
3000,
|
phoneNumberId ? 0 : 3000,
|
||||||
ticket.id
|
ticket.id
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -318,6 +318,51 @@ const verifyQueue = async (
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mediaTypeWhatsappOfficial = (mimetype: string): object => {
|
||||||
|
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 => {
|
const isValidMsg = (msg: any): boolean => {
|
||||||
if (msg.from === "status@broadcast") return false;
|
if (msg.from === "status@broadcast") return false;
|
||||||
if (
|
if (
|
||||||
|
@ -363,43 +408,19 @@ const botTransferTicket = async (
|
||||||
};
|
};
|
||||||
|
|
||||||
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 });
|
||||||
},
|
},
|
||||||
3000,
|
phoneNumberId ? 0 : 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);
|
||||||
|
|
||||||
|
@ -414,8 +435,12 @@ const _clear_lst = () => {
|
||||||
setWhatsappId(whatsappIdsSplited, true);
|
setWhatsappId(whatsappIdsSplited, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMessage = async (msg: any, wbot: any): Promise<void> => {
|
const handleMessage = async (
|
||||||
if (!msg.fromMe) {
|
msg: any,
|
||||||
|
wbot: any,
|
||||||
|
whatsAppOfficial?: any
|
||||||
|
): Promise<void> => {
|
||||||
|
if (!msg.fromMe && !whatsAppOfficial) {
|
||||||
_clear_lst();
|
_clear_lst();
|
||||||
|
|
||||||
let index = lst.findIndex((x: any) => x.id == msg.id.id);
|
let index = lst.findIndex((x: any) => x.id == msg.id.id);
|
||||||
|
@ -502,7 +527,12 @@ const handleMessage = async (msg: any, wbot: any): Promise<void> => {
|
||||||
|
|
||||||
const unreadMessages = msg.fromMe ? 0 : chat.unreadCount;
|
const unreadMessages = msg.fromMe ? 0 : chat.unreadCount;
|
||||||
|
|
||||||
const contact = await verifyContact(msgContact);
|
const contact = !whatsAppOfficial
|
||||||
|
? await verifyContact(msgContact)
|
||||||
|
: await verifyContact(null, {
|
||||||
|
number: wbot.msgContact.number,
|
||||||
|
name: wbot.msgContact.name
|
||||||
|
});
|
||||||
|
|
||||||
if (
|
if (
|
||||||
unreadMessages === 0 &&
|
unreadMessages === 0 &&
|
||||||
|
@ -653,6 +683,11 @@ 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", {
|
||||||
|
@ -685,6 +720,8 @@ export {
|
||||||
handleMsgAck,
|
handleMsgAck,
|
||||||
lst,
|
lst,
|
||||||
verifyMessage,
|
verifyMessage,
|
||||||
|
verifyMediaMessage,
|
||||||
verifyContact,
|
verifyContact,
|
||||||
isValidMsg,
|
isValidMsg,
|
||||||
|
mediaTypeWhatsappOfficial
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,19 +2,46 @@ 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 (id: string | number): Promise<Whatsapp> => {
|
const ShowWhatsAppService = async (
|
||||||
const whatsapp = await Whatsapp.findByPk(id, {
|
id: string | number | null,
|
||||||
include: [
|
whatsAppOfficial?: any
|
||||||
{
|
): Promise<Whatsapp> => {
|
||||||
model: Queue,
|
let whatsapp;
|
||||||
as: "queues",
|
|
||||||
attributes: ["id", "name", "color", "greetingMessage"]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
order: [["queues", "id", "ASC"]]
|
|
||||||
});
|
|
||||||
|
|
||||||
// console.log('kkkkkkkkkkkkkkkkkkkk: ', whatsapp)
|
if (id) {
|
||||||
|
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);
|
||||||
|
|
|
@ -1,27 +1,30 @@
|
||||||
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 LinearProgress from "@material-ui/core/LinearProgress";
|
import LinearProgress from "@material-ui/core/LinearProgress"
|
||||||
import { makeStyles } from "@material-ui/core";
|
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 { WhatsAppsContext } from "../../context/WhatsApp/WhatsAppsContext"
|
||||||
|
|
||||||
|
|
||||||
|
import api from "../../services/api"
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
maxWidth: {
|
maxWidth: {
|
||||||
|
@ -33,30 +36,64 @@ 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)
|
||||||
|
const { whatsApps } = useContext(WhatsAppsContext)
|
||||||
|
|
||||||
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 } })
|
|
||||||
if (userQueues.length === 1) setSelectedQueue(userQueues[0].id)
|
const delayDebounceFn = setTimeout(() => {
|
||||||
setQueues(userQueues)
|
|
||||||
}, [user]);
|
const fetchMatchQueueUserOfficialWhatsapp = async () => {
|
||||||
|
try {
|
||||||
|
|
||||||
|
const { data } = await api.get("/whatsapp/official/matchQueueUser", { params: { userId: user.id, queueId: selectedQueue }, })
|
||||||
|
|
||||||
|
console.log('DATA: ', data)
|
||||||
|
|
||||||
|
setQueues(data)
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchMatchQueueUserOfficialWhatsapp()
|
||||||
|
|
||||||
|
}, 500)
|
||||||
|
return () => clearTimeout(delayDebounceFn)
|
||||||
|
|
||||||
|
}, [user])
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
onClose();
|
onClose()
|
||||||
};
|
}
|
||||||
|
|
||||||
|
const handleSaveTicket = useCallback(async (contactId, userId, queueId, selectedWhatsId, whatsQueue, queues) => {
|
||||||
|
|
||||||
|
console.log(`contactId: ${contactId}, userId: ${userId}, queueId: ${queueId}, selectedWhatsId: ${selectedWhatsId}, whatsQueue: ${whatsQueue}, queues: ${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
|
||||||
|
@ -65,8 +102,12 @@ 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 () => {
|
||||||
|
@ -76,32 +117,79 @@ const ContactCreateTicketModal = ({ modalOpen, onClose, contactId }) => {
|
||||||
userId: userId,
|
userId: userId,
|
||||||
queueId: queueId,
|
queueId: queueId,
|
||||||
status: "open",
|
status: "open",
|
||||||
});
|
whatsappId: selectedWhatsId
|
||||||
history.push(`/tickets/${ticket.id}`);
|
})
|
||||||
} catch (err) {
|
history.push(`/tickets/${ticket.id}`)
|
||||||
toastError(err);
|
|
||||||
}
|
|
||||||
if (isMounted.current) setLoading(false);
|
|
||||||
|
|
||||||
};
|
setWhatsQueue(null)
|
||||||
ticketCreate();
|
setSelectedWhatsId(null)
|
||||||
}, 300);
|
} catch (err) {
|
||||||
return () => clearTimeout(delayDebounceFn);
|
toastError(err)
|
||||||
|
}
|
||||||
|
if (isMounted.current) setLoading(false)
|
||||||
|
|
||||||
|
}
|
||||||
|
ticketCreate()
|
||||||
|
}, 300)
|
||||||
|
return () => clearTimeout(delayDebounceFn)
|
||||||
|
|
||||||
}, [history])
|
}, [history])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (modalOpen && queues.length <= 1) {
|
|
||||||
handleSaveTicket(contactId, user.id, selectedQueue)
|
|
||||||
}
|
|
||||||
return () => {
|
|
||||||
isMounted.current = false;
|
|
||||||
};
|
|
||||||
}, [modalOpen, contactId, user.id, selectedQueue, handleSaveTicket, queues.length]);
|
|
||||||
|
|
||||||
if (modalOpen && queues.length <= 1) {
|
if (selectedQueue && selectedQueue.length === 0 || !selectedQueue) {
|
||||||
return <LinearProgress />
|
setDisabled(true)
|
||||||
}
|
setWhatsQueue(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (modalOpen && queues.length <= 1) {
|
||||||
|
// handleSaveTicket(contactId, user.id, selectedQueue, selectedWhatsId, whatsQueue, queues)
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (!Array.isArray(whatsQueue)) {
|
||||||
|
setSelectedWhatsId(null)
|
||||||
|
setWhatsQueue(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
isMounted.current = false
|
||||||
|
}
|
||||||
|
}, [modalOpen, contactId, user.id, selectedQueue, handleSaveTicket, queues.length, selectedWhatsId, whatsQueue, queues])
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
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 }, })
|
||||||
|
|
||||||
|
setWhatsQueue(data)
|
||||||
|
|
||||||
|
setDisabled(false)
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetChMatchQueueOfficialWhatsapp()
|
||||||
|
|
||||||
|
}, 500)
|
||||||
|
return () => clearTimeout(delayDebounceFn)
|
||||||
|
|
||||||
|
}, [selectedQueue, user.id])
|
||||||
|
|
||||||
|
|
||||||
|
// if (modalOpen && queues.length <= 1) {
|
||||||
|
// return <LinearProgress />
|
||||||
|
// }
|
||||||
|
|
||||||
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 }}>
|
||||||
|
@ -117,9 +205,10 @@ const ContactCreateTicketModal = ({ modalOpen, onClose, contactId }) => {
|
||||||
label={i18n.t("Filas")}
|
label={i18n.t("Filas")}
|
||||||
>
|
>
|
||||||
<MenuItem value={''}> </MenuItem>
|
<MenuItem value={''}> </MenuItem>
|
||||||
{queues.map(({ id, color, name }) => (
|
{queues.map(({ id, color, name, disable }) => (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
key={id}
|
key={id}
|
||||||
|
disabled={disable}
|
||||||
value={id}
|
value={id}
|
||||||
onMouseEnter={() => setItemHover(id)}
|
onMouseEnter={() => setItemHover(id)}
|
||||||
onMouseLeave={() => setItemHover(-1)}
|
onMouseLeave={() => setItemHover(-1)}
|
||||||
|
@ -131,6 +220,31 @@ 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}
|
||||||
|
@ -141,16 +255,17 @@ 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)}
|
onClick={() => handleSaveTicket(contactId, user.id, selectedQueue, selectedWhatsId, whatsQueue, queues)}
|
||||||
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
|
|
@ -388,6 +388,7 @@ const MessageInput = ({ ticketStatus }) => {
|
||||||
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) {
|
||||||
|
|
|
@ -56,7 +56,7 @@ const MessageOptionsMenu = ({ message, menuOpen, handleClose, anchorEl }) => {
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
>
|
>
|
||||||
{message.fromMe && (
|
{message.fromMe && (
|
||||||
<MenuItem onClick={handleOpenConfirmationModal}>
|
<MenuItem onClick={handleOpenConfirmationModal} disabled={message?.phoneNumberId ? true : false}>
|
||||||
{i18n.t("messageOptionsMenu.delete")}
|
{i18n.t("messageOptionsMenu.delete")}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -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,7 +38,7 @@ const useStyles = makeStyles(theme => ({
|
||||||
noShadow: {
|
noShadow: {
|
||||||
boxShadow: "none !important",
|
boxShadow: "none !important",
|
||||||
},
|
},
|
||||||
}));
|
}))
|
||||||
|
|
||||||
|
|
||||||
let _fifo
|
let _fifo
|
||||||
|
@ -64,82 +64,76 @@ let _fifo
|
||||||
|
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
socket.on("onlineStatus", (data) => {
|
socket.on("onlineStatus", (data) => {
|
||||||
|
|
||||||
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) => {
|
||||||
|
|
||||||
|
@ -157,159 +151,145 @@ 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 => {
|
||||||
|
|
||||||
|
const ticketIndex = prevState.findIndex(t => t.id === data.ticket.id)
|
||||||
|
|
||||||
setNotifications(prevState => {
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 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 (
|
||||||
<>
|
<>
|
||||||
|
@ -357,7 +337,7 @@ const NotificationsPopOver = () => {
|
||||||
|
|
||||||
</Popover>
|
</Popover>
|
||||||
</>
|
</>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
export default NotificationsPopOver;
|
export default NotificationsPopOver
|
||||||
|
|
Loading…
Reference in New Issue