Merge branch 'master' of github.com:AdrianoRobson/projeto-hit

pull/22/head
Adriano 2024-03-15 16:36:41 -03:00
commit e864e0b97f
26 changed files with 848 additions and 374 deletions

View File

@ -126,21 +126,12 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
const validNumber = await CheckIsValidContact(newContact.number); const validNumber = await CheckIsValidContact(newContact.number);
// const validNumber: any = await CheckContactNumber(newContact.number)
if (!validNumber) { if (!validNumber) {
throw new AppError("ERR_WAPP_CHECK_CONTACT"); throw new AppError("ERR_WAPP_CHECK_CONTACT");
} }
const profilePicUrl = await GetProfilePicUrl(validNumber); const profilePicUrl = await GetProfilePicUrl(validNumber);
console.log("xxxxxxxxxxx profilePicUrl: ", profilePicUrl);
// console.log(`newContact.name: ${newContact.name}\n
// newContact.number: ${newContact.number}\n
// newContact.email: ${newContact.email}\n
// newContact.extraInfo: ${newContact.extraInfo}`)
let name = newContact.name; let name = newContact.name;
let number = validNumber; let number = validNumber;
let email = newContact.email; let email = newContact.email;

View File

@ -21,6 +21,7 @@ import sendWhatsAppMessageOfficialAPI from "../helpers/sendWhatsAppMessageOffici
import Whatsapp from "../models/Whatsapp"; import Whatsapp from "../models/Whatsapp";
import checkLastClientMsg24hs from "../helpers/CheckLastClientMsg24hs"; import checkLastClientMsg24hs from "../helpers/CheckLastClientMsg24hs";
import AppError from "../errors/AppError"; import AppError from "../errors/AppError";
import { get } from "../helpers/RedisClient";
type IndexQuery = { type IndexQuery = {
pageNumber: string; pageNumber: string;
@ -97,7 +98,8 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
} }
const name = params.find((p: any) => p?.template_name); const name = params.find((p: any) => p?.template_name);
const { language }: any = params?.find((p: any) => p?.language) || 'pt_BR' const { language }: any =
params?.find((p: any) => p?.language) || "pt_BR";
const { template_name } = name; const { template_name } = name;

View File

@ -5,11 +5,9 @@ import DeleteQueueService from "../services/QueueService/DeleteQueueService";
import ListQueuesService from "../services/QueueService/ListQueuesService"; import ListQueuesService from "../services/QueueService/ListQueuesService";
import ShowQueueService from "../services/QueueService/ShowQueueService"; import ShowQueueService from "../services/QueueService/ShowQueueService";
import UpdateQueueService from "../services/QueueService/UpdateQueueService"; import UpdateQueueService from "../services/QueueService/UpdateQueueService";
import Queue from "../models/Queue" import Queue from "../models/Queue";
import AppError from "../errors/AppError" import AppError from "../errors/AppError";
import { get, set } from "../helpers/RedisClient"; import { del, get, set } from "../helpers/RedisClient";
export const index = async (req: Request, res: Response): Promise<Response> => { export const index = async (req: Request, res: Response): Promise<Response> => {
const queues = await ListQueuesService(); const queues = await ListQueuesService();
@ -125,7 +123,7 @@ export const customization = async (
await set("ura", ura); await set("ura", ura);
const _ura = await get("ura"); const _ura = await get({ key: "ura", parse: true });
console.log("_URA: ", _ura); console.log("_URA: ", _ura);
return res.status(200).json({ new_queues }); return res.status(200).json({ new_queues });
@ -164,6 +162,8 @@ export const remove = async (
await DeleteQueueService(queueId); await DeleteQueueService(queueId);
await del(`queue:${queueId}`);
const io = getIO(); const io = getIO();
io.emit("queue", { io.emit("queue", {
action: "delete", action: "delete",

View File

@ -75,6 +75,7 @@ import GetProfilePicUrl from "../services/WbotServices/GetProfilePicUrl";
import CreateContactService from "../services/ContactServices/CreateContactService"; import CreateContactService from "../services/ContactServices/CreateContactService";
import { botSendMessage } from "../services/WbotServices/wbotMessageListener"; import { botSendMessage } from "../services/WbotServices/wbotMessageListener";
import WhatsappQueue from "../models/WhatsappQueue"; import WhatsappQueue from "../models/WhatsappQueue";
import { get } from "../helpers/RedisClient"
export const index = async (req: Request, res: Response): Promise<Response> => { export const index = async (req: Request, res: Response): Promise<Response> => {
const { const {
@ -93,7 +94,7 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
let queueIds: number[] = []; let queueIds: number[] = [];
if (queueIdsStringified) { if (queueIdsStringified && queueIdsStringified.trim().length > 0) {
queueIds = JSON.parse(queueIdsStringified); queueIds = JSON.parse(queueIdsStringified);
} }

View File

@ -12,7 +12,7 @@ import DeleteUserService from "../services/UserServices/DeleteUserService";
import ListUser from "../services/UserServices/ListUserParamiterService"; import ListUser from "../services/UserServices/ListUserParamiterService";
import User from "../models/User"; import User from "../models/User";
import { get, set } from "../helpers/RedisClient"; import { del, get, set } from "../helpers/RedisClient";
import { import {
startWhoIsOnlineMonitor, startWhoIsOnlineMonitor,
@ -27,6 +27,7 @@ import { splitDateTime } from "../helpers/SplitDateTime";
import ListUserByWhatsappQueuesService from "../services/UserServices/ListUserByWhatsappQueuesService"; import ListUserByWhatsappQueuesService from "../services/UserServices/ListUserByWhatsappQueuesService";
import { json } from "sequelize"; import { json } from "sequelize";
import { getSettingValue } from "../helpers/WhaticketSettings"; import { getSettingValue } from "../helpers/WhaticketSettings";
import { setBotInfo } from "../helpers/SetBotInfo";
type IndexQuery = { type IndexQuery = {
searchParam: string; searchParam: string;
@ -111,7 +112,6 @@ export const all = async (req: Request, res: Response): Promise<Response> => {
); );
if (getSettingValue("queueTransferByWhatsappScope")?.value == "enabled") { if (getSettingValue("queueTransferByWhatsappScope")?.value == "enabled") {
if (!userId) return res.json({ users: [], queues: [] }); if (!userId) return res.json({ users: [], queues: [] });
const obj = await ListUserByWhatsappQueuesService( const obj = await ListUserByWhatsappQueuesService(
@ -167,6 +167,11 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
queueIds queueIds
}); });
if (user) {
const { id, name } = user;
await set(`user:${id}`, { id, name });
}
const io = getIO(); const io = getIO();
io.emit("user", { io.emit("user", {
action: "create", action: "create",
@ -270,34 +275,11 @@ export const update = async (
let user: any = await UpdateUserService({ userData, userId }); let user: any = await UpdateUserService({ userData, userId });
if (user?.name?.trim() == "botqueue") { await setBotInfo(user);
let botInfo;
if ( if (user) {
user?.queues?.length > 0 && const { id, name } = user;
user.queues[0]?.name?.trim() == "botqueue" await set(`user:${id}`, { id, name });
) {
botInfo = JSON.stringify({
userId: user.id,
queueId: user.queues[0].id,
botIsOnQueue: true
});
botInfo = JSON.parse(botInfo);
await set("botInfo", botInfo);
} else if (
user?.queues?.length == 0 ||
user.queues[0]?.name?.trim() != "botqueue"
) {
botInfo = JSON.stringify({
userId: user.id,
queueId: 0,
botIsOnQueue: false
});
botInfo = JSON.parse(botInfo);
await set("botInfo", botInfo);
}
} }
const io = getIO(); const io = getIO();
@ -323,6 +305,8 @@ export const remove = async (
await DeleteUserService(userId); await DeleteUserService(userId);
del(`user:${userId}`);
const io = getIO(); const io = getIO();
io.emit("user", { io.emit("user", {
action: "delete", action: "delete",

View File

@ -42,6 +42,7 @@ import { getSettingValue } from "../helpers/WhaticketSettings";
import ListWhatsAppsNumber from "../services/WhatsappService/ListWhatsAppsNumber"; import ListWhatsAppsNumber from "../services/WhatsappService/ListWhatsAppsNumber";
import SettingTicket from "../models/SettingTicket"; import SettingTicket from "../models/SettingTicket";
import { Op } from "sequelize"; import { Op } from "sequelize";
import { del, get, set } from "../helpers/RedisClient";
interface WhatsappData { interface WhatsappData {
name: string; name: string;
@ -229,6 +230,25 @@ export const weebhook = async (
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; let type = message.type;
const contact_to_exist = await get({
key: "whatsapp:*",
value: `${contact_to}`
});
if (contact_to_exist == null) {
console.log(
"WHATSAPP OFFICIAL",
" | CONCTACT_FROM: ",
contact_from,
" | CONTACT_TO: ",
contact_to
);
console.log(
"NUMBER IGNORED. WHATSAPP NUMBER FROM ANOTHER OMNIHIT APPLICATION!"
);
return res.status(403).json({ error: "Unauthorized" });
}
let wbot = {}; let wbot = {};
let msg = {}; let msg = {};
let contacts = req.body.entry[0].changes[0].value.contacts[0]; let contacts = req.body.entry[0].changes[0].value.contacts[0];
@ -248,6 +268,10 @@ export const weebhook = async (
}); });
if (type == "text") { if (type == "text") {
if (!message?.text?.body) {
return res.status(400).json({ error: "body not found" });
}
type = "chat"; type = "chat";
msg = { msg = {
...msg, ...msg,
@ -255,6 +279,10 @@ export const weebhook = async (
type type
}; };
} else { } else {
if (!message[message?.type]?.id) {
return res.status(400).json({ error: "id not found" });
}
const mediaId = message[message.type].id; const mediaId = message[message.type].id;
const mimetype = message[message.type].mime_type; const mimetype = message[message.type].mime_type;
@ -382,6 +410,16 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
number: getNumberFromName(name), number: getNumberFromName(name),
client_url: `${process.env.BACKEND_URL_RAW}:${process.env.PORT}` client_url: `${process.env.BACKEND_URL_RAW}:${process.env.PORT}`
}); });
} else {
await set(
`whatsapp:${whatsapp.id}`,
JSON.stringify({
number: whatsapp?.number,
id: whatsapp?.id,
greetingMessage: whatsapp?.greetingMessage,
phoneNumberId: whatsapp?.phoneNumberId
})
);
} }
const io = getIO(); const io = getIO();
@ -421,13 +459,14 @@ export const update = async (
return res.status(200).json({ message: invalidPhoneName }); return res.status(200).json({ message: invalidPhoneName });
} }
const { urlApi, isOfficial, phoneNumberId, wabaId } = whatsappData; const { urlApi, isOfficial, phoneNumberId, number, wabaId } = whatsappData;
const invalid = checkWhatsAppData({ const invalid = checkWhatsAppData({
urlApi, urlApi,
isOfficial, isOfficial,
phoneNumberId, phoneNumberId,
wabaId wabaId,
number
}); });
if (invalid) { if (invalid) {
@ -440,6 +479,7 @@ export const update = async (
} else if (!isOfficial) { } else if (!isOfficial) {
whatsappData.phoneNumberId = ""; whatsappData.phoneNumberId = "";
whatsappData.wabaId = ""; whatsappData.wabaId = "";
whatsappData.number = "";
} }
const { whatsapp, oldDefaultWhatsapp } = await UpdateWhatsAppService({ const { whatsapp, oldDefaultWhatsapp } = await UpdateWhatsAppService({
@ -454,6 +494,16 @@ export const update = async (
number: getNumberFromName(whatsapp.name), number: getNumberFromName(whatsapp.name),
client_url: `${process.env.BACKEND_URL_RAW}:${process.env.PORT}` client_url: `${process.env.BACKEND_URL_RAW}:${process.env.PORT}`
}); });
} else {
await set(
`whatsapp:${whatsapp.id}`,
JSON.stringify({
number: whatsapp?.number,
id: whatsapp?.id,
greetingMessage: whatsapp?.greetingMessage,
phoneNumberId: whatsapp?.phoneNumberId
})
);
} }
const io = getIO(); const io = getIO();
@ -491,6 +541,8 @@ export const remove = async (
}); });
} }
await del(`whatsapp:${whatsappId}`);
let whats = await ListWhatsAppsNumber(whatsappId); let whats = await ListWhatsAppsNumber(whatsappId);
// Remove tickets business hours config // Remove tickets business hours config

View File

@ -0,0 +1,15 @@
import { QueryInterface, DataTypes } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.addColumn("Messages", "fromAgent", {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false
});
},
down: (queryInterface: QueryInterface) => {
return queryInterface.removeColumn("Messages", "fromAgent");
}
};

View File

@ -5,8 +5,7 @@ import ListUsersService from "../services/UserServices/ListUsersService";
import { get } from "./RedisClient"; import { get } from "./RedisClient";
const _botIsOnQueue = async (botName: string) => { const _botIsOnQueue = async (botName: string) => {
const botInfo = await get({ key: "botInfo", parse: true });
const botInfo = await get("botInfo");
if ( if (
botInfo && botInfo &&

View File

@ -13,15 +13,14 @@ import { WhatsIndex } from "./LoadBalanceWhatsSameQueue";
interface Request { interface Request {
userId?: string | number; userId?: string | number;
queueId?: string | number; queueId?: string | number;
ignoreNoWhatsappFound?: boolean
} }
//const GetDefaultWhatsApp = async (userId?: string | number): Promise<Whatsapp> => {
const GetDefaultWhatsApp = async ({ const GetDefaultWhatsApp = async ({
userId, userId,
queueId queueId,
ignoreNoWhatsappFound = false
}: Request): Promise<any> => { }: Request): Promise<any> => {
// test del
let defaultWhatsapp = await Whatsapp.findOne({ let defaultWhatsapp = await Whatsapp.findOne({
where: { isDefault: true } where: { isDefault: true }
}); });
@ -56,17 +55,16 @@ const GetDefaultWhatsApp = async ({
} }
} else { } else {
defaultWhatsapp = await Whatsapp.findOne({ defaultWhatsapp = await Whatsapp.findOne({
where: { status: "CONNECTED" } where: { status: "CONNECTED", isOfficial: false }
}); });
} }
} }
if (!defaultWhatsapp) { if (!defaultWhatsapp && !ignoreNoWhatsappFound) {
throw new AppError("ERR_NO_DEF_WAPP_FOUND"); throw new AppError("ERR_NO_DEF_WAPP_FOUND");
} }
return defaultWhatsapp; return defaultWhatsapp;
//
}; };
export default GetDefaultWhatsApp; export default GetDefaultWhatsApp;

View File

@ -6,28 +6,65 @@ type WhatsappData = {
contactId: string; contactId: string;
identifier: string; identifier: string;
value?: string; value?: string;
history?: string;
};
type getData = {
key: string;
value?: string;
parse?: boolean;
}; };
export async function set(key: string, value: string | object) { export async function set(key: string, value: string | object) {
await redis.set(key, JSON.stringify(value)); if (typeof value == "object") await redis.set(key, JSON.stringify(value));
else {
await redis.set(key, value);
}
} }
export async function get(key: string) { export async function getSimple(key: string) {
const value: any = await redis.get(key); const value: any = await redis.get(key);
return JSON.parse(value); return value;
} }
export async function clearAllKeys() { export async function get({ key, value, parse }: getData) {
if (key.includes("*")) {
const keys = await redis.keys(key);
if (keys.length > 0) {
for (const key of keys) {
const val = await redis.get(key);
if (val.includes(value)) {
if (parse) return JSON.parse(val);
return val;
}
}
}
return null;
} else {
const value: any = await redis.get(key);
if (parse) return JSON.parse(value);
return value;
}
}
export async function del(key: string) {
await redis.del(key);
}
export async function clearAllKeys(...keys: string[]) {
for (const key of keys) {
// Retrieve all keys matching the pattern '*' // Retrieve all keys matching the pattern '*'
const keys = await redis.keys("user:*"); const del_keys = await redis.keys(key);
// If there are keys, delete them // If there are keys, delete them
if (keys.length > 0) { if (del_keys.length > 0) {
console.log('keys: ', keys) console.log("del_keys: ", del_keys);
await redis.del(...keys); await redis.del(...del_keys);
}
} }
} }
export async function findByContain( export async function findByContain(
key: string, key: string,
@ -62,7 +99,8 @@ export async function createObject({
whatsappId, whatsappId,
contactId, contactId,
identifier, identifier,
value value,
history = ""
}: WhatsappData) { }: WhatsappData) {
const key = `whatsappId:${whatsappId}:contactId:${contactId}:identifier:${identifier}`; const key = `whatsappId:${whatsappId}:contactId:${contactId}:identifier:${identifier}`;
const result = await redis.hmset( const result = await redis.hmset(
@ -74,7 +112,9 @@ export async function createObject({
"identifier", "identifier",
identifier, identifier,
"value", "value",
value value,
"history",
history
); );
await redis.expire(key, 300); await redis.expire(key, 300);
@ -102,7 +142,8 @@ export async function findObject(
"whatsappId", "whatsappId",
"contactId", "contactId",
"identifier", "identifier",
"value" "value",
"history"
); );
return result; return result;
} }

View File

@ -0,0 +1,33 @@
import { get, set } from "../helpers/RedisClient";
export async function setBotInfo(user: any) {
if (user?.name?.trim() == "botqueue") {
let botInfo;
if (
user?.queues?.length > 0 &&
user.queues[0]?.name?.trim() == "botqueue"
) {
botInfo = JSON.stringify({
userId: user.id,
queueId: user.queues[0].id,
botIsOnQueue: true
});
botInfo = JSON.parse(botInfo);
await set("botInfo", botInfo);
} else if (
user?.queues?.length == 0 ||
user.queues[0]?.name?.trim() != "botqueue"
) {
botInfo = JSON.stringify({
userId: user.id,
queueId: 0,
botIsOnQueue: false
});
botInfo = JSON.parse(botInfo);
await set("botInfo", botInfo);
}
}
}

View File

@ -31,6 +31,10 @@ class Message extends Model<Message> {
@Column @Column
fromMe: boolean; fromMe: boolean;
@Default(false)
@Column
fromAgent: boolean;
@Column(DataType.TEXT) @Column(DataType.TEXT)
body: string; body: string;

View File

@ -23,7 +23,11 @@ import fs from "fs";
import dir from "path"; import dir from "path";
import { getSettingValue } from "./helpers/WhaticketSettings"; import { getSettingValue } from "./helpers/WhaticketSettings";
import loadSettings from "./helpers/LoadSettings"; import loadSettings from "./helpers/LoadSettings";
import { clearAllKeys, set } from "./helpers/RedisClient"; import { clearAllKeys, get, set } from "./helpers/RedisClient";
import ShowUserService from "./services/UserServices/ShowUserService";
import { json } from "sequelize";
import { setBotInfo } from "./helpers/SetBotInfo";
import Queue from "./models/Queue";
const server = app.listen(process.env.PORT, () => { const server = app.listen(process.env.PORT, () => {
logger.info(`Server started on port: ${process.env.PORT}`); logger.info(`Server started on port: ${process.env.PORT}`);
@ -44,27 +48,54 @@ gracefulShutdown(server);
(async () => { (async () => {
console.log("os.tmpdir(): ", os.tmpdir()); console.log("os.tmpdir(): ", os.tmpdir());
await clearAllKeys(); await clearAllKeys("user:*", "whatsapp:*", "queue:*");
const users = await User.findAll(); const users = await User.findAll();
for (const user of users) { for (const user of users) {
const { id, name } = user; const { id, name } = user;
if (name == "botqueue") {
const userService = await ShowUserService(id);
await setBotInfo(userService);
}
await set(`user:${id}`, { id, name }); await set(`user:${id}`, { id, name });
} }
// const queues = await Queue.findAll();
// for (const queue of queues) {
// const { id, greetingMessage, name } = queue;
// await set(`queue:${id}`, { id, name, greetingMessage });
// }
loadSettings(); loadSettings();
let whatsapps: any = await Whatsapp.findAll({ let whatsapps: any = await Whatsapp.findAll({
attributes: ["id", "url", "phoneNumberId"] attributes: ["id", "url", "phoneNumberId", "number", "greetingMessage"]
}); });
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]; const { phoneNumberId, id, greetingMessage } = whatsapps[i];
if (phoneNumberId) continue; if (phoneNumberId) {
await set(
`whatsapp:${whatsapps[i].dataValues.id}`,
JSON.stringify({
number: whatsapps[i].dataValues.number,
id,
greetingMessage,
phoneNumberId
})
);
}
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`

View File

@ -13,6 +13,7 @@ interface MessageData {
read?: boolean; read?: boolean;
mediaType?: string; mediaType?: string;
mediaUrl?: string; mediaUrl?: string;
fromAgent?: boolean;
} }
interface Request { interface Request {
messageData: MessageData; messageData: MessageData;

View File

@ -1,6 +1,7 @@
import * as Yup from "yup"; import * as Yup from "yup";
import AppError from "../../errors/AppError"; import AppError from "../../errors/AppError";
import Queue from "../../models/Queue"; import Queue from "../../models/Queue";
import { set } from "../../helpers/RedisClient";
interface QueueData { interface QueueData {
name: string; name: string;
@ -9,9 +10,7 @@ interface QueueData {
} }
const CreateQueueService = async (queueData: QueueData): Promise<Queue> => { const CreateQueueService = async (queueData: QueueData): Promise<Queue> => {
try { try {
const { color, name } = queueData; const { color, name } = queueData;
const queueSchema = Yup.object().shape({ const queueSchema = Yup.object().shape({
@ -64,13 +63,14 @@ const CreateQueueService = async (queueData: QueueData): Promise<Queue> => {
const queue = await Queue.create(queueData); const queue = await Queue.create(queueData);
return queue; // const { id, greetingMessage } = queue;
// await set(`queue:${id}`, { id, name, greetingMessage });
return queue;
} catch (error: any) { } catch (error: any) {
console.error('===> Error on CreateQueueService.ts file: \n', error) console.error("===> Error on CreateQueueService.ts file: \n", error);
throw new AppError(error.message); throw new AppError(error.message);
} }
}; };
export default CreateQueueService; export default CreateQueueService;

View File

@ -3,6 +3,7 @@ import * as Yup from "yup";
import AppError from "../../errors/AppError"; import AppError from "../../errors/AppError";
import Queue from "../../models/Queue"; import Queue from "../../models/Queue";
import ShowQueueService from "./ShowQueueService"; import ShowQueueService from "./ShowQueueService";
import { set } from "../../helpers/RedisClient"
interface QueueData { interface QueueData {
name?: string; name?: string;
@ -14,9 +15,7 @@ const UpdateQueueService = async (
queueId: number | string, queueId: number | string,
queueData: QueueData queueData: QueueData
): Promise<Queue> => { ): Promise<Queue> => {
try { try {
const { color, name } = queueData; const { color, name } = queueData;
const queueSchema = Yup.object().shape({ const queueSchema = Yup.object().shape({
@ -70,13 +69,14 @@ const UpdateQueueService = async (
await queue.update(queueData); await queue.update(queueData);
return queue; // const { id, greetingMessage } = queue;
// await set(`queue:${id}`, { id, name, greetingMessage });
return queue;
} catch (error: any) { } catch (error: any) {
console.error('===> Error on UpdateQueueService.ts file: \n', error) console.error("===> Error on UpdateQueueService.ts file: \n", error);
throw new AppError(error.message); throw new AppError(error.message);
} }
}; };
export default UpdateQueueService; export default UpdateQueueService;

View File

@ -29,7 +29,8 @@ const FindOrCreateTicketServiceBot = async (
} }
}); });
const { queues, greetingMessage } = await ShowWhatsAppService(whatsappId); const { queues, greetingMessage, phoneNumberId } =
await ShowWhatsAppService(whatsappId);
//Habilitar esse caso queira usar o bot //Habilitar esse caso queira usar o bot
@ -107,7 +108,8 @@ const FindOrCreateTicketServiceBot = async (
userId: botInfo.userIdBot, userId: botInfo.userIdBot,
isGroup: !!groupContact, isGroup: !!groupContact,
unreadMessages, unreadMessages,
whatsappId whatsappId,
phoneNumberId
}); });
console.log('yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy') console.log('yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy')

View File

@ -7,14 +7,17 @@ import Queue from "../../models/Queue";
import Message from "../../models/Message"; import Message from "../../models/Message";
import { userInfo } from "os"; import { userInfo } from "os";
import { Op, where } from "sequelize"; import { Op, QueryTypes, where } from "sequelize";
import { Sequelize } from "sequelize"; import { Sequelize } from "sequelize";
import moment from "moment"; import moment from "moment";
const dbConfig = require("../../config/database");
const sequelize = new Sequelize(dbConfig);
import { startOfDay, endOfDay, parseISO, getDate } from "date-fns"; import { startOfDay, endOfDay, parseISO, getDate } from "date-fns";
import { string } from "yup/lib/locale"; import { string } from "yup/lib/locale";
import Whatsapp from "../../models/Whatsapp"; import Whatsapp from "../../models/Whatsapp";
import Query from "mysql2/typings/mysql/lib/protocol/sequences/Query"
interface Request { interface Request {
userId: string | number; userId: string | number;
@ -41,43 +44,41 @@ const ShowTicketReport = async ({
queueId queueId
}: Request): Promise<Response> => { }: Request): Promise<Response> => {
let where_clause: any = {}; let where_clause: any = {};
// let where_clause_msg: any = {}; let query = "";
if (userId !== "0") { if (userId !== "0") {
where_clause.userid = userId; where_clause.userid = userId;
query = `AND t.userId = ${userId}`;
} }
if (createdOrUpdated === "updated") {
where_clause = {
...where_clause,
updatedAt: {
[Op.gte]: startDate + " 00:00:00.000000",
[Op.lte]: endDate + " 23:59:59.999999"
}
};
}
if (createdOrUpdated === "created") {
where_clause = {
...where_clause,
createdAt: {
[Op.gte]: startDate + " 00:00:00.000000",
[Op.lte]: endDate + " 23:59:59.999999"
}
};
}
let { userid, ...where_clause_msg } = where_clause;
if (queueId) { if (queueId) {
where_clause.queueId = queueId; where_clause.queueId = queueId;
query = `AND t.queueId = ${queueId}`;
} }
const limit = 40; const limit = 40;
const offset = limit * (+pageNumber - 1); const offset = limit * (+pageNumber - 1);
const createdAtOrUpdatedAt =
createdOrUpdated == "created" ? "createdAt" : "updatedAt";
const _ticketsId = await sequelize.query(
`SELECT t.id
FROM Tickets t
INNER JOIN (
SELECT DISTINCT ticketId
FROM Messages
WHERE ${createdAtOrUpdatedAt} >= '${startDate} 00:00:00' AND ${createdAtOrUpdatedAt} <= '${endDate} 23:59:59'
) AS m ON m.ticketId = t.id ${query};`,
{ type: QueryTypes.SELECT }
);
console.log('QUERY: ', query)
const { count, rows: tickets } = await Ticket.findAndCountAll({ const { count, rows: tickets } = await Ticket.findAndCountAll({
where: where_clause, where: {
id: { [Op.in]: _ticketsId.map((t: any) => t.id) }
},
limit, limit,
offset, offset,
@ -108,7 +109,6 @@ const ShowTicketReport = async ({
model: Message, model: Message,
required: true, required: true,
separate: true, separate: true,
where: where_clause_msg ,
attributes: [ attributes: [
"body", "body",

View File

@ -1,27 +1,60 @@
import axios from "axios";
import AppError from "../../errors/AppError"; import AppError from "../../errors/AppError";
import endPointQuery from "../../helpers/EndPointQuery"; import endPointQuery from "../../helpers/EndPointQuery";
import GetDefaultWhatsApp from "../../helpers/GetDefaultWhatsApp"; import GetDefaultWhatsApp from "../../helpers/GetDefaultWhatsApp";
import { getWbot } from "../../libs/wbot"; import { getWbot } from "../../libs/wbot";
const CheckIsValidContact = async (number: string, ignoreThrow?:boolean): Promise<any> => { const CheckIsValidContact = async (
number: string,
ignoreThrow?: boolean
): Promise<any> => {
const defaultWhatsapp = await GetDefaultWhatsApp({
ignoreNoWhatsappFound: true
});
const defaultWhatsapp = await GetDefaultWhatsApp({}); let isValidNumber;
if (defaultWhatsapp) {
const wbot_url = await getWbot(defaultWhatsapp.id); const wbot_url = await getWbot(defaultWhatsapp.id);
const isValidNumber = await endPointQuery(`${wbot_url}/api/validate`, { mobile: `${number}`, }) let { data } = await endPointQuery(`${wbot_url}/api/validate`, {
mobile: `${number}`
});
if(ignoreThrow) return isValidNumber?.data?.number; if (data?.isValid) {
isValidNumber = data;
// console.log('isValidNumber.data.number: ', isValidNumber.data.number) }
}
try { try {
let _status: any;
// const isValidNumber = await wbot.isRegisteredUser(`${number}@c.us`); if (!isValidNumber) {
if (!isValidNumber || isValidNumber && !isValidNumber.data.isValid) { const { data, status } = await axios.post(
`${process.env.WHATS_NUMBER_VALIDATOR_URL}/api/validate`,
{ mobile: number },
{
headers: {
"Content-Type": "application/json"
}
}
);
isValidNumber = data;
_status = status;
}
if (ignoreThrow) return isValidNumber?.number;
console.log('_status: ', _status)
if (_status && _status == 422) throw new AppError("ERR_NO_WAPP_FOUND");
if (!isValidNumber || (isValidNumber && !isValidNumber.isValid)) {
throw new AppError("invalidNumber"); throw new AppError("invalidNumber");
} }
if (isValidNumber && isValidNumber?.isValid) return isValidNumber.number;
} catch (err: any) { } catch (err: any) {
if (err.message === "invalidNumber") { if (err.message === "invalidNumber") {
throw new AppError("ERR_WAPP_INVALID_CONTACT"); throw new AppError("ERR_WAPP_INVALID_CONTACT");
@ -29,10 +62,6 @@ const CheckIsValidContact = async (number: string, ignoreThrow?:boolean): Promis
throw new AppError("ERR_WAPP_CHECK_CONTACT"); throw new AppError("ERR_WAPP_CHECK_CONTACT");
} }
if (isValidNumber && isValidNumber.data.isValid)
return isValidNumber.data.number
}; };
export default CheckIsValidContact; export default CheckIsValidContact;

View File

@ -1,23 +1,47 @@
import axios from "axios";
import endPointQuery from "../../helpers/EndPointQuery"; import endPointQuery from "../../helpers/EndPointQuery";
import GetDefaultWhatsApp from "../../helpers/GetDefaultWhatsApp"; import GetDefaultWhatsApp from "../../helpers/GetDefaultWhatsApp";
import { getWbot } from "../../libs/wbot"; import { getWbot } from "../../libs/wbot";
const GetProfilePicUrl = async (number: string): Promise<any> => { const GetProfilePicUrl = async (number: string): Promise<any> => {
const defaultWhatsapp = await GetDefaultWhatsApp({
ignoreNoWhatsappFound: true
});
const defaultWhatsapp = await GetDefaultWhatsApp({}); let profilePicUrl;
if (defaultWhatsapp) {
const wbot_url = await getWbot(defaultWhatsapp.id); const wbot_url = await getWbot(defaultWhatsapp.id);
let profilePicUrl = await endPointQuery(`${wbot_url}/api/GetProfilePicUrl`, { number: `${number}`, }) const {data} = await endPointQuery(`${wbot_url}/api/GetProfilePicUrl`, {
number: `${number}`
});
console.log('profilePicUrl.data.data: ', profilePicUrl.data.data) if (data?.data) {
profilePicUrl = data.data;
if (profilePicUrl && profilePicUrl.data.data) { }
return profilePicUrl.data.data;
} }
return null try {
if (!profilePicUrl) {
const { data } = await axios.post(
`${process.env.WHATS_NUMBER_VALIDATOR_URL}/api/GetProfilePicUrl`,
{ number },
{
headers: {
"Content-Type": "application/json"
}
}
);
profilePicUrl = data?.data;
}
if (profilePicUrl) {
return profilePicUrl;
}
} catch (error) {}
return null;
}; };
export default GetProfilePicUrl; export default GetProfilePicUrl;

View File

@ -92,13 +92,14 @@ import {
createObject, createObject,
findByContain, findByContain,
findObject, findObject,
get get,
getSimple
} from "../../helpers/RedisClient"; } from "../../helpers/RedisClient";
import FindOrCreateTicketServiceBot from "../TicketServices/FindOrCreateTicketServiceBot"; import FindOrCreateTicketServiceBot from "../TicketServices/FindOrCreateTicketServiceBot";
import ShowTicketService from "../TicketServices/ShowTicketService"; import ShowTicketService from "../TicketServices/ShowTicketService";
import ShowQueuesByUser from "../UserServices/ShowQueuesByUser"; import ShowQueuesByUser from "../UserServices/ShowQueuesByUser";
import ListWhatsappQueuesByUserQueue from "../UserServices/ListWhatsappQueuesByUserQueue"; import ListWhatsappQueuesByUserQueue from "../UserServices/ListWhatsappQueuesByUserQueue";
import CreateContactService from "../ContactServices/CreateContactService" import CreateContactService from "../ContactServices/CreateContactService";
var lst: any[] = getWhatsappIds(); var lst: any[] = getWhatsappIds();
@ -175,9 +176,14 @@ const verifyMediaMessage = async (
mediaUrl: media.filename, mediaUrl: media.filename,
mediaType: media.mimetype.split("/")[0], mediaType: media.mimetype.split("/")[0],
quotedMsgId: quotedMsg, quotedMsgId: quotedMsg,
phoneNumberId: msg?.phoneNumberId phoneNumberId: msg?.phoneNumberId,
fromAgent: false
}; };
if (msg?.fromMe) {
messageData = { ...messageData, fromAgent: true };
}
if (!ticket?.phoneNumberId) { if (!ticket?.phoneNumberId) {
if (!media.filename) { if (!media.filename) {
const ext = media.mimetype.split("/")[1].split(";")[0]; const ext = media.mimetype.split("/")[1].split(";")[0];
@ -280,18 +286,33 @@ const verifyMessage = async (
contact: Contact, contact: Contact,
quotedMsg?: any quotedMsg?: any
) => { ) => {
const messageData = { let messageData = {
id: msg.id.id, id: msg.id.id,
ticketId: ticket.id, ticketId: ticket.id,
contactId: msg.fromMe ? undefined : contact.id, contactId: msg.fromMe ? undefined : contact.id,
body: msg.body, body: msg.body,
fromMe: msg.fromMe, fromMe: msg.fromMe,
fromAgent: false,
mediaType: msg.type, mediaType: msg.type,
read: msg.fromMe, read: msg.fromMe,
quotedMsgId: quotedMsg, quotedMsgId: quotedMsg,
phoneNumberId: msg?.phoneNumberId phoneNumberId: msg?.phoneNumberId
}; };
if (msg?.fromMe) {
const botInfo = await BotIsOnQueue("botqueue");
if (botInfo.isOnQueue) {
const ura: any = await get({ key: "ura" });
if (ura && !ura.includes(JSON.stringify(msg?.body))) {
messageData = { ...messageData, fromAgent: true };
}
} else if (msg?.body?.trim().length > 0 && !/\u200e/.test(msg.body[0])) {
messageData = { ...messageData, fromAgent: true };
}
}
await ticket.update({ lastMessage: msg.body }); await ticket.update({ lastMessage: msg.body });
await CreateMessageService({ messageData }); await CreateMessageService({ messageData });
@ -318,14 +339,15 @@ const verifyQueue = async (
selectedOption = 1; selectedOption = 1;
choosenQueue = queues[+selectedOption - 1]; choosenQueue = queues[+selectedOption - 1];
} else { } else {
selectedOption = msg.body; selectedOption = msg?.body;
if (selectedOption && selectedOption.trim().length > 0) {
//////////////// EXTRAIR APENAS O NÚMERO /////////////////// //////////////// EXTRAIR APENAS O NÚMERO ///////////////////
selectedOption = selectedOption.replace(/[^1-9]/g, ""); selectedOption = selectedOption.replace(/[^1-9]/g, "");
/////////////////////////////////// ///////////////////////////////////
choosenQueue = queues[+selectedOption - 1]; choosenQueue = queues[+selectedOption - 1];
} }
}
if (choosenQueue) { if (choosenQueue) {
// Atualizando o status do ticket para mostrar notificação para o atendente da fila escolhida pelo usuário. De queueChoice para pending // Atualizando o status do ticket para mostrar notificação para o atendente da fila escolhida pelo usuário. De queueChoice para pending
@ -348,13 +370,14 @@ const verifyQueue = async (
ticketId: ticket.id ticketId: ticket.id
}); });
const data = await get("ura"); const data = await get({ key: "ura", parse: true });
await createObject({ await createObject({
whatsappId: `${ticket.whatsappId}`, whatsappId: `${ticket.whatsappId}`,
contactId: `${ticket.contactId}`, contactId: `${ticket.contactId}`,
identifier: "ura", identifier: "ura",
value: data[1].id value: data[1].id,
history: `|${data[1].id}`
}); });
botSendMessage(ticket, data[1].value); botSendMessage(ticket, data[1].value);
@ -507,8 +530,6 @@ const transferTicket = async (
) => { ) => {
const botInfo = await BotIsOnQueue("botqueue"); const botInfo = await BotIsOnQueue("botqueue");
console.log("kkkkkkkkkkkkkkkkkkkkk queueName: ", queueName);
const queuesWhatsGreetingMessage = await queuesOutBot( const queuesWhatsGreetingMessage = await queuesOutBot(
wbot, wbot,
botInfo.botQueueId botInfo.botQueueId
@ -964,7 +985,7 @@ const handleMessage = async (
const menu = async (userTyped: string, whatsappId: any, contactId: any) => { const menu = async (userTyped: string, whatsappId: any, contactId: any) => {
let lastId = await findObject(whatsappId, contactId, "ura"); let lastId = await findObject(whatsappId, contactId, "ura");
const data: any = await get("ura"); const data: any = await get({ key: "ura", parse: true });
console.log("lastId[0]: ", lastId[0]); console.log("lastId[0]: ", lastId[0]);
@ -973,7 +994,8 @@ const menu = async (userTyped: string, whatsappId: any, contactId: any) => {
whatsappId, whatsappId,
contactId, contactId,
identifier: "ura", identifier: "ura",
value: data[1].id value: data[1].id,
history: `|${data[1].id}`
}); });
} }
@ -983,7 +1005,7 @@ const menu = async (userTyped: string, whatsappId: any, contactId: any) => {
if ( if (
lastId && lastId &&
lastId.length == 4 && (lastId.length == 4 || lastId.length == 5) &&
lastId[3] && lastId[3] &&
lastId[3].trim().length > 0 lastId[3].trim().length > 0
) { ) {
@ -993,23 +1015,49 @@ const menu = async (userTyped: string, whatsappId: any, contactId: any) => {
o.value.toLowerCase() == userTyped.toLowerCase() o.value.toLowerCase() == userTyped.toLowerCase()
); );
// TEST DEL if (!option && userTyped != "0" && userTyped != "#") {
console.log("OPTION: ", option);
if (!option && userTyped != "0") {
if (!existSubMenu()) { if (!existSubMenu()) {
const response = await mainOptionsMenu(userTyped); const response = await mainOptionsMenu(userTyped);
if (response) return response; if (response) return response;
else { else {
console.log("kkkkkkkkkkkkkkkkkkk"); let uraOptionSelected = await findObject(
whatsappId,
contactId,
"ura"
);
uraOptionSelected = uraOptionSelected[4].split("|");
if (uraOptionSelected.length == 1) {
await createObject({ await createObject({
whatsappId, whatsappId,
contactId, contactId,
identifier: "ura", identifier: "ura",
value: data[1].id value: data[1].id,
history: `|${data[1].id}`
}); });
return data[1]; return data[1];
} else if (uraOptionSelected.length > 1) {
const id = uraOptionSelected[uraOptionSelected.length - 1];
console.log(" ID FROM THE MENU/SUBMENU: ", id);
const history = await historyUra(whatsappId, contactId, id);
await createObject({
whatsappId,
contactId,
identifier: "ura",
value: id,
history
});
let response: any = data.find((o: any) => o.id == id);
return response;
}
} }
} }
} }
@ -1017,19 +1065,16 @@ const menu = async (userTyped: string, whatsappId: any, contactId: any) => {
if (option) { if (option) {
let response: any = data.find((o: any) => o.idmaster == option.id); let response: any = data.find((o: any) => o.idmaster == option.id);
console.log(" RESPONSE OPTION: ", response, " | OPTION: ", option);
console.log( let history: any = await historyUra(whatsappId, contactId, response.id);
"RRRRRRRRRRRRRRRRRRRRRRRRRRRRR response: ",
response,
" | option: ",
option
);
await createObject({ await createObject({
whatsappId, whatsappId,
contactId, contactId,
identifier: "ura", identifier: "ura",
value: response.id value: response.id,
history
}); });
return response; return response;
@ -1038,25 +1083,41 @@ const menu = async (userTyped: string, whatsappId: any, contactId: any) => {
whatsappId, whatsappId,
contactId, contactId,
identifier: "ura", identifier: "ura",
value: data[1].id value: data[1].id,
history: `|${data[1].id}`
}); });
return data[1]; return data[1];
} else { } else if (userTyped == "#") {
console.log("INVALID SEARCH"); let uraOptionSelected = await findObject(whatsappId, contactId, "ura");
let response = await existSubMenu(); uraOptionSelected = uraOptionSelected[4].split("|").filter(Boolean);
if (response) return response;
return { let id = uraOptionSelected[0];
value: data.find((o: any) => o.id == lastId[3])?.value
};
// return { let history = `|${uraOptionSelected[0]}`;
// value: `Você digitou uma opçao inválida!\n\n${
// data.find((o: any) => o.id == lastId[3])?.value if (uraOptionSelected.length > 1) {
// }\n\nDigite 0 para voltar ao menu ` const idRemove = uraOptionSelected[uraOptionSelected.length - 1];
// };
history = await historyUra(whatsappId, contactId, idRemove, true);
const lstIds = history.split("|").filter(Boolean);
id = lstIds[lstIds.length - 1];
}
await createObject({
whatsappId,
contactId,
identifier: "ura",
value: id,
history
});
let response: any = data.find((o: any) => o.id == id);
return response;
} }
} }
@ -1069,18 +1130,29 @@ const menu = async (userTyped: string, whatsappId: any, contactId: any) => {
} }
async function mainOptionsMenu(userTyped: any) { async function mainOptionsMenu(userTyped: any) {
let currentMenu = await findObject(whatsappId, contactId, "ura");
const menuValues = data
.filter((m: any) => m.idmaster == currentMenu[3])
.map((m: any) => m.value);
let menuOption = data.find( let menuOption = data.find(
(o: any) => o.value.toLowerCase() == userTyped.toLowerCase() (o: any) =>
o.value.toLowerCase() == userTyped.toLowerCase() &&
menuValues.includes(userTyped.toLowerCase())
); );
console.log("============> menuOption OPTION: ", menuOption);
if (menuOption) { if (menuOption) {
let response = data.find((o: any) => o.idmaster == menuOption.id); let response = data.find((o: any) => o.idmaster == menuOption.id);
if (response) { if (response) {
let history = await historyUra(whatsappId, contactId, response.id);
await createObject({ await createObject({
whatsappId, whatsappId,
contactId, contactId,
identifier: "ura", identifier: "ura",
value: response.id value: response.id,
history
}); });
return response; return response;
@ -1189,6 +1261,31 @@ export {
mediaTypeWhatsappOfficial, mediaTypeWhatsappOfficial,
botSendMessage botSendMessage
}; };
async function historyUra(
whatsappId: any,
contactId: any,
id: any,
remove?: boolean
) {
let uraOptionSelected = await findObject(whatsappId, contactId, "ura");
let history = "";
console.log("SELECED OPTION uraOptionSelected: ", uraOptionSelected);
if (remove) {
return uraOptionSelected[4]?.replace(`|${id}`, "");
}
if (uraOptionSelected && uraOptionSelected.length == 5) {
if (!uraOptionSelected[4]?.includes(`${id}`))
history += `${uraOptionSelected[4]}|${id}`;
else history = `${uraOptionSelected[4]}`;
} else {
history = `|${id}`;
}
return history;
}
async function whatsappInfo(whatsappId: string | number) { async function whatsappInfo(whatsappId: string | number) {
return await Whatsapp.findByPk(whatsappId); return await Whatsapp.findByPk(whatsappId);
} }

View File

@ -22,6 +22,7 @@ interface WhatsappData {
greetingMessage?: string; greetingMessage?: string;
farewellMessage?: string; farewellMessage?: string;
queueIds?: number[]; queueIds?: number[];
number?:string;
} }
interface Request { interface Request {
@ -52,6 +53,7 @@ const UpdateWhatsAppService = async ({
phoneNumberId, phoneNumberId,
wabaId, wabaId,
isOfficial, isOfficial,
number,
url, url,
urlApi, urlApi,
session, session,
@ -116,6 +118,7 @@ const UpdateWhatsAppService = async ({
isOfficial, isOfficial,
phoneNumberId, phoneNumberId,
wabaId, wabaId,
number,
classification classification
}); });

View File

@ -1,26 +1,26 @@
import React, { useState, useEffect, useRef } from "react"; import React, { useState, useEffect, useRef } from "react"
import * as Yup from "yup"; import * as Yup from "yup"
import { Formik, FieldArray, Form, Field } from "formik"; import { Formik, FieldArray, Form, Field } from "formik"
import { toast } from "react-toastify"; import { toast } from "react-toastify"
import { makeStyles } from "@material-ui/core/styles"; import { makeStyles } from "@material-ui/core/styles"
import { green } from "@material-ui/core/colors"; import { green } from "@material-ui/core/colors"
import Button from "@material-ui/core/Button"; import Button from "@material-ui/core/Button"
import TextField from "@material-ui/core/TextField"; import TextField from "@material-ui/core/TextField"
import Dialog from "@material-ui/core/Dialog"; import Dialog from "@material-ui/core/Dialog"
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 Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography"
import IconButton from "@material-ui/core/IconButton"; import IconButton from "@material-ui/core/IconButton"
import DeleteOutlineIcon from "@material-ui/icons/DeleteOutline"; import DeleteOutlineIcon from "@material-ui/icons/DeleteOutline"
import CircularProgress from "@material-ui/core/CircularProgress"; import CircularProgress from "@material-ui/core/CircularProgress"
import { i18n } from "../../translate/i18n"; import { i18n } from "../../translate/i18n"
import api from "../../services/api"; import api from "../../services/api"
import toastError from "../../errors/toastError"; import toastError from "../../errors/toastError"
const useStyles = makeStyles(theme => ({ const useStyles = makeStyles(theme => ({
root: { root: {
@ -50,7 +50,7 @@ const useStyles = makeStyles(theme => ({
marginTop: -12, marginTop: -12,
marginLeft: -12, marginLeft: -12,
}, },
})); }))
const ContactSchema = Yup.object().shape({ const ContactSchema = Yup.object().shape({
name: Yup.string() name: Yup.string()
@ -63,72 +63,74 @@ const ContactSchema = Yup.object().shape({
.max(50, "Too Long!"), .max(50, "Too Long!"),
// email: Yup.string().email("Invalid email"), // email: Yup.string().email("Invalid email"),
}); })
const ContactModal = ({ open, onClose, contactId, initialValues, onSave }) => { const ContactModal = ({ open, onClose, contactId, initialValues, onSave }) => {
const classes = useStyles(); const classes = useStyles()
const isMounted = useRef(true); const isMounted = useRef(true)
const initialState = { const initialState = {
name: "", name: "",
number: "", number: "",
email: "", email: "",
useDialogflow: true, useDialogflow: true,
}; }
const [contact, setContact] = useState(initialState); const [contact, setContact] = useState(initialState)
const [isSaving, setSaving] = useState(false)
useEffect(() => { useEffect(() => {
return () => { return () => {
isMounted.current = false; isMounted.current = false
}; }
}, []); }, [])
useEffect(() => { useEffect(() => {
const fetchContact = async () => { const fetchContact = async () => {
if (initialValues) { if (initialValues) {
setContact(prevState => { setContact(prevState => {
return { ...prevState, ...initialValues }; return { ...prevState, ...initialValues }
}); })
} }
if (!contactId) return; if (!contactId) return
try { try {
const { data } = await api.get(`/contacts/${contactId}`); const { data } = await api.get(`/contacts/${contactId}`)
if (isMounted.current) { if (isMounted.current) {
setContact(data); setContact(data)
} }
} catch (err) { } catch (err) {
toastError(err); toastError(err)
}
} }
};
fetchContact(); fetchContact()
}, [contactId, open, initialValues]); }, [contactId, open, initialValues])
const handleClose = () => { const handleClose = () => {
onClose(); onClose()
setContact(initialState); setContact(initialState)
}; }
const handleSaveContact = async values => { const handleSaveContact = async values => {
try { try {
if (contactId) { if (contactId) {
await api.put(`/contacts/${contactId}`, values); await api.put(`/contacts/${contactId}`, values)
handleClose(); handleClose()
} else { } else {
const { data } = await api.post("/contacts", values); const { data } = await api.post("/contacts", values)
if (onSave) { if (onSave) {
onSave(data); onSave(data)
} }
handleClose(); handleClose()
} }
toast.success(i18n.t("contactModal.success")); toast.success(i18n.t("contactModal.success"))
} catch (err) { } catch (err) {
toastError(err); toastError(err)
}
setSaving(false)
} }
};
return ( return (
<div className={classes.root}> <div className={classes.root}>
@ -143,10 +145,11 @@ const ContactModal = ({ open, onClose, contactId, initialValues, onSave }) => {
enableReinitialize={true} enableReinitialize={true}
validationSchema={ContactSchema} validationSchema={ContactSchema}
onSubmit={(values, actions) => { onSubmit={(values, actions) => {
setSaving(true)
setTimeout(() => { setTimeout(() => {
handleSaveContact(values); handleSaveContact(values)
actions.setSubmitting(false); actions.setSubmitting(false)
}, 400); }, 400)
}} }}
> >
{({ values, errors, touched, isSubmitting }) => ( {({ values, errors, touched, isSubmitting }) => (
@ -256,14 +259,14 @@ const ContactModal = ({ open, onClose, contactId, initialValues, onSave }) => {
<Button <Button
type="submit" type="submit"
color="primary" color="primary"
disabled={isSubmitting} disabled={isSaving}
variant="contained" variant="contained"
className={classes.btnWrapper} className={classes.btnWrapper}
> >
{contactId {contactId
? `${i18n.t("contactModal.buttons.okEdit")}` ? `${i18n.t("contactModal.buttons.okEdit")}`
: `${i18n.t("contactModal.buttons.okAdd")}`} : `${i18n.t("contactModal.buttons.okAdd")}`}
{isSubmitting && ( {isSaving && (
<CircularProgress <CircularProgress
size={24} size={24}
className={classes.buttonProgress} className={classes.buttonProgress}
@ -276,7 +279,7 @@ const ContactModal = ({ open, onClose, contactId, initialValues, onSave }) => {
</Formik> </Formik>
</Dialog> </Dialog>
</div> </div>
); )
}; }
export default ContactModal; export default ContactModal

View File

@ -0,0 +1,135 @@
import React, { useState, useEffect } from "react"
import Box from '@mui/material/Box'
import Button from '@mui/material/Button'
import Dialog from '@mui/material/Dialog'
import DialogActions from '@mui/material/DialogActions'
import DialogContent from '@mui/material/DialogContent'
import DialogContentText from '@mui/material/DialogContentText'
import DialogTitle from '@mui/material/DialogTitle'
import FormControl from '@mui/material/FormControl'
import InputLabel from '@mui/material/InputLabel'
import MenuItem from '@mui/material/MenuItem'
import Select from '@mui/material/Select'
export default function MaxWidthDialog(props) {
const [open, setOpen] = useState(false)
const [fullWidth,] = useState(true)
const [currency, setCurrency] = useState(props.reportOption)
const [textOption, setTextOption] = useState('')
useEffect(() => {
// props.func(currency)
if(currency === '2' || currency === '3'){
setTextOption('Retorna apenas tickets com status: fechado')
}
else{
setTextOption('Retorna todos os tickets com status: aberto, fechado, pendente')
}
}, [currency, props])
const handleClickOpen = () => {
setOpen(true)
}
const handleClose = () => {
props.func(currency)
setOpen(false)
}
const handleMaxWidthChange = (event) => {
setCurrency(event.target.value)
}
return (
<React.Fragment>
<Button variant="outlined" onClick={handleClickOpen}>
CSV ALL
</Button>
<Dialog
fullWidth={fullWidth}
maxWidth={'sm'}
open={open}
onClose={null}
>
<DialogTitle>Relatórios</DialogTitle>
<DialogContent>
<DialogContentText>
Escolha uma opção do tipo de relatório abaixo
</DialogContentText>
<Box
noValidate
component="form"
sx={{
display: 'flex',
flexDirection: 'column',
m: 'auto',
width: 'fit-content',
}}
>
<FormControl sx={{ mt: 2, minWidth: 420 }}>
<InputLabel htmlFor="opcoes">opcoes</InputLabel>
<Select
autoFocus
value={currency}
onChange={handleMaxWidthChange}
label="opcoes"
inputProps={{
name: 'opcoes',
id: 'opcoes',
}}
>
{props.currencies.map((option, index) => (
<MenuItem key={index} value={option.value}> {option.label} </MenuItem>
))}
</Select>
</FormControl>
{/* <FormControlLabel
sx={{ mt: 1 }}
control={
<Switch checked={fullWidth} onChange={handleFullWidthChange} />
}
label="Full width"
/> */}
</Box>
</DialogContent>
<div style={{ display: 'flex', justifyContent: "center" }}>{textOption}</div>
<div style={{ display: 'flex', justifyContent: "right" }}>
<DialogActions>
<Button onClick={() => setOpen(false)}>Cancelar</Button>
</DialogActions>
<DialogActions>
<Button onClick={handleClose}>Ok</Button>
</DialogActions>
</div>
</Dialog>
</React.Fragment>
)
}

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect, useReducer, useContext } from "react" import React, { useState, useEffect, useReducer, useContext, useCallback } from "react"
import MainContainer from "../../components/MainContainer" import MainContainer from "../../components/MainContainer"
import api from "../../services/api" import api from "../../services/api"
import SelectField from "../../components/Report/SelectField" import SelectField from "../../components/Report/SelectField"
@ -17,6 +17,8 @@ import Checkbox from '@mui/material/Checkbox'
import { Button } from "@material-ui/core" import { Button } from "@material-ui/core"
import ReportModal from "../../components/ReportModal" import ReportModal from "../../components/ReportModal"
import ReportModalType from "../../components/ReportModalType"
import MaterialTable from 'material-table' import MaterialTable from 'material-table'
import LogoutIcon from '@material-ui/icons/CancelOutlined' import LogoutIcon from '@material-ui/icons/CancelOutlined'
@ -34,6 +36,9 @@ import Switch from '@mui/material/Switch'
const label = { inputProps: { 'aria-label': 'Size switch demo' } } const label = { inputProps: { 'aria-label': 'Size switch demo' } }
const report = [{ 'value': '1', 'label': 'Atendimento por atendentes' }, { 'value': '2', 'label': 'Usuários online/offline' }] const report = [{ 'value': '1', 'label': 'Atendimento por atendentes' }, { 'value': '2', 'label': 'Usuários online/offline' }]
const reportOptType = [{ 'value': '1', 'label': 'Padrão' }, { 'value': '2', 'label': 'Sintético' }, { 'value': '3', 'label': 'Analítico' }]
const reducerQ = (state, action) => { const reducerQ = (state, action) => {
@ -276,21 +281,16 @@ const Report = () => {
const [hasMore, setHasMore] = useState(false) const [hasMore, setHasMore] = useState(false)
const [pageNumberTickets, setTicketsPageNumber] = useState(1) const [pageNumberTickets, setTicketsPageNumber] = useState(1)
const [totalCountTickets, setTotalCountTickets] = useState(0) const [totalCountTickets, setTotalCountTickets] = useState(0)
const [pageNumber, setPageNumber] = useState(1) const [pageNumber, setPageNumber] = useState(1)
const [users, dispatch] = useReducer(reducer, []) const [users, dispatch] = useReducer(reducer, [])
const [startDate, setDatePicker1] = useState(new Date()) const [startDate, setDatePicker1] = useState(new Date())
const [endDate, setDatePicker2] = useState(new Date()) const [endDate, setDatePicker2] = useState(new Date())
const [userId, setUser] = useState(null) const [userId, setUser] = useState(null)
const [query, dispatchQ] = useReducer(reducerQ, []) const [query, dispatchQ] = useReducer(reducerQ, [])
const [reportOption, setReport] = useState('1') const [reportOption, setReport] = useState('1')
const [reporList,] = useState(report) const [reporList,] = useState(report)
const [profile, setProfile] = useState('') const [profile, setProfile] = useState('')
const [dataRows, setData] = useState([]) const [dataRows, setData] = useState([])
const [onQueueStatus, setOnQueueProcessStatus] = useState(undefined) const [onQueueStatus, setOnQueueProcessStatus] = useState(undefined)
const [csvFile, setCsvFile] = useState() const [csvFile, setCsvFile] = useState()
const [selectedValue, setSelectedValue] = useState('created') const [selectedValue, setSelectedValue] = useState('created')
@ -298,6 +298,11 @@ const Report = () => {
const [queues, setQueues] = useState([]) const [queues, setQueues] = useState([])
const [queueId, setQueue] = useState(null) const [queueId, setQueue] = useState(null)
const [reportTypeList,] = useState(reportOptType)
const [reportType, setReportType] = useState('1')
const [firstLoad, setFirstLoad] = useState(true);
useEffect(() => { useEffect(() => {
dispatch({ type: "RESET" }) dispatch({ type: "RESET" })
dispatchQ({ type: "RESET" }) dispatchQ({ type: "RESET" })
@ -306,6 +311,14 @@ const Report = () => {
}, [searchParam, profile]) }, [searchParam, profile])
useEffect(() => {
if (firstLoad) {
setFirstLoad(false)
} else {
}
}, [firstLoad]);
useEffect(() => { useEffect(() => {
//setLoading(true); //setLoading(true);
@ -337,16 +350,14 @@ const Report = () => {
useEffect(() => { useEffect(() => {
//setLoading(true); //setLoading(true);
if (firstLoad) return
const delayDebounceFn = setTimeout(() => { const delayDebounceFn = setTimeout(() => {
setLoading(true) setLoading(true)
const fetchQueries = async () => { const fetchQueries = async () => {
try { try {
if (reportOption === '1') { if (reportOption === '1') {
// const { data } = await api.get("/reports/", { params: { userId: userId ? userId : 0, startDate: convertAndFormatDate(startDate), endDate: convertAndFormatDate(endDate), pageNumber: pageNumberTickets }, })
const { data } = await api.get("/reports/", { params: { userId, startDate, endDate, pageNumber: pageNumberTickets, createdOrUpdated: selectedValue, queueId }, userQueues: userA.queues }) const { data } = await api.get("/reports/", { params: { userId, startDate, endDate, pageNumber: pageNumberTickets, createdOrUpdated: selectedValue, queueId }, userQueues: userA.queues })
let ticketsQueue = data.tickets let ticketsQueue = data.tickets
@ -426,6 +437,19 @@ const Report = () => {
setReport(data) setReport(data)
} }
// Get from report type option
const reportTypeValue = (data) => {
console.log('DATA: ', data)
let type = '1'
if (data === '1') type = 'default'
if (data === '2') type = 'synthetic'
if (data === '3') type = 'analytic'
handleCSVMessages(type)
setReportType(data)
}
useEffect(() => { useEffect(() => {
if (reportOption === '1') { if (reportOption === '1') {
@ -500,7 +524,7 @@ const Report = () => {
const handleCSVMessages = () => { const handleCSVMessages = (type = 'default') => {
const fetchQueries = async () => { const fetchQueries = async () => {
@ -519,7 +543,8 @@ const Report = () => {
userId: userId, userId: userId,
startDate: startDate, startDate: startDate,
endDate: endDate endDate: endDate
} },
query_type: type
}) })
const onQueueStatus = querySavedOnQueue.data.queueStatus const onQueueStatus = querySavedOnQueue.data.queueStatus
@ -639,7 +664,10 @@ const Report = () => {
case 'empty': case 'empty':
return ( return (
<> <>
<Button {query && query.length > 0 &&
<ReportModalType currencies={reportTypeList} func={reportTypeValue} reportOption={reportType} />
}
{/* <Button
disabled={query && query.length > 0 ? false : true} disabled={query && query.length > 0 ? false : true}
variant="contained" variant="contained"
color="primary" color="primary"
@ -648,7 +676,8 @@ const Report = () => {
}} }}
> >
{"CSV ALL"} {"CSV ALL"}
</Button>
</Button> */}
</>) </>)
case 'pending' || 'processing': case 'pending' || 'processing':