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

@ -124,22 +124,13 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
newContact.number = addStartPhoneNumber(newContact.number);
const validNumber = await CheckIsValidContact(newContact.number);
// const validNumber: any = await CheckContactNumber(newContact.number)
const validNumber = await CheckIsValidContact(newContact.number);
if (!validNumber) {
throw new AppError("ERR_WAPP_CHECK_CONTACT");
}
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}`)
const profilePicUrl = await GetProfilePicUrl(validNumber);
let name = newContact.name;
let number = validNumber;

View File

@ -21,6 +21,7 @@ import sendWhatsAppMessageOfficialAPI from "../helpers/sendWhatsAppMessageOffici
import Whatsapp from "../models/Whatsapp";
import checkLastClientMsg24hs from "../helpers/CheckLastClientMsg24hs";
import AppError from "../errors/AppError";
import { get } from "../helpers/RedisClient";
type IndexQuery = {
pageNumber: string;
@ -35,7 +36,7 @@ type MessageData = {
params: any;
};
export const index = async (req: Request, res: Response): Promise<Response> => {
export const index = async (req: Request, res: Response): Promise<Response> => {
const { ticketId } = req.params;
const { pageNumber } = req.query as IndexQuery;
@ -97,7 +98,8 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
}
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;

View File

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

View File

@ -75,8 +75,9 @@ import GetProfilePicUrl from "../services/WbotServices/GetProfilePicUrl";
import CreateContactService from "../services/ContactServices/CreateContactService";
import { botSendMessage } from "../services/WbotServices/wbotMessageListener";
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 {
pageNumber,
status,
@ -93,9 +94,9 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
let queueIds: number[] = [];
if (queueIdsStringified) {
if (queueIdsStringified && queueIdsStringified.trim().length > 0) {
queueIds = JSON.parse(queueIdsStringified);
}
}
const { tickets, count, hasMore } = await ListTicketsService({
searchParam,
@ -109,7 +110,7 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
unlimited,
searchParamContent
});
return res.status(200).json({ tickets, count, hasMore });
};

View File

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

View File

@ -42,6 +42,7 @@ import { getSettingValue } from "../helpers/WhaticketSettings";
import ListWhatsAppsNumber from "../services/WhatsappService/ListWhatsAppsNumber";
import SettingTicket from "../models/SettingTicket";
import { Op } from "sequelize";
import { del, get, set } from "../helpers/RedisClient";
interface WhatsappData {
name: string;
@ -229,6 +230,25 @@ export const weebhook = async (
req.body.entry[0].changes[0].value.metadata.display_phone_number;
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 msg = {};
let contacts = req.body.entry[0].changes[0].value.contacts[0];
@ -248,6 +268,10 @@ export const weebhook = async (
});
if (type == "text") {
if (!message?.text?.body) {
return res.status(400).json({ error: "body not found" });
}
type = "chat";
msg = {
...msg,
@ -255,6 +279,10 @@ export const weebhook = async (
type
};
} else {
if (!message[message?.type]?.id) {
return res.status(400).json({ error: "id not found" });
}
const mediaId = message[message.type].id;
const mimetype = message[message.type].mime_type;
@ -382,6 +410,16 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
number: getNumberFromName(name),
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();
@ -421,13 +459,14 @@ export const update = async (
return res.status(200).json({ message: invalidPhoneName });
}
const { urlApi, isOfficial, phoneNumberId, wabaId } = whatsappData;
const { urlApi, isOfficial, phoneNumberId, number, wabaId } = whatsappData;
const invalid = checkWhatsAppData({
urlApi,
isOfficial,
phoneNumberId,
wabaId
wabaId,
number
});
if (invalid) {
@ -440,6 +479,7 @@ export const update = async (
} else if (!isOfficial) {
whatsappData.phoneNumberId = "";
whatsappData.wabaId = "";
whatsappData.number = "";
}
const { whatsapp, oldDefaultWhatsapp } = await UpdateWhatsAppService({
@ -454,6 +494,16 @@ export const update = async (
number: getNumberFromName(whatsapp.name),
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();
@ -491,6 +541,8 @@ export const remove = async (
});
}
await del(`whatsapp:${whatsappId}`);
let whats = await ListWhatsAppsNumber(whatsappId);
// Remove tickets business hours config
@ -572,5 +624,5 @@ const checkWhatsAppData = ({
return { message: "Phone number is required!" };
} else if (!isOfficial && (!urlApi || urlApi.trim() == "")) {
return { message: "urlApi is required!" };
}
}
};

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

@ -4,9 +4,8 @@ const fs = require("fs");
import ListUsersService from "../services/UserServices/ListUsersService";
import { get } from "./RedisClient";
const _botIsOnQueue = async (botName: string) => {
const botInfo = await get("botInfo");
const _botIsOnQueue = async (botName: string) => {
const botInfo = await get({ key: "botInfo", parse: true });
if (
botInfo &&
@ -19,8 +18,8 @@ const _botIsOnQueue = async (botName: string) => {
botQueueId: botInfo.queueId,
isOnQueue: botInfo.botIsOnQueue
};
}
return { userIdBot: null, botQueueId: null, isOnQueue: false };
}
return { userIdBot: null, botQueueId: null, isOnQueue: false };
};
export default _botIsOnQueue;

View File

@ -6,27 +6,26 @@ import UserQueue from "../models/UserQueue";
import { Op, where } from "sequelize";
import wbotByUserQueue from "../helpers/GetWbotByUserQueue";
import wbotByUserQueue from "../helpers/GetWbotByUserQueue";
import { WhatsIndex } from "./LoadBalanceWhatsSameQueue";
interface Request {
userId?: string | number;
queueId?: string | number;
ignoreNoWhatsappFound?: boolean
}
//const GetDefaultWhatsApp = async (userId?: string | number): Promise<Whatsapp> => {
const GetDefaultWhatsApp = async ({
userId,
queueId
}: Request): Promise<any> => {
// test del
queueId,
ignoreNoWhatsappFound = false
}: Request): Promise<any> => {
let defaultWhatsapp = await Whatsapp.findOne({
where: { isDefault: true }
});
if (!defaultWhatsapp) {
if (!defaultWhatsapp) {
if (userId) {
let whatsapps = await wbotByUserQueue({ userId, queueId });
@ -54,19 +53,18 @@ const GetDefaultWhatsApp = async ({
where: { status: "CONNECTED" }
});
}
} else {
} else {
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");
}
return defaultWhatsapp;
//
return defaultWhatsapp;
};
export default GetDefaultWhatsApp;

View File

@ -6,28 +6,65 @@ type WhatsappData = {
contactId: string;
identifier: string;
value?: string;
history?: string;
};
type getData = {
key: string;
value?: string;
parse?: boolean;
};
export async function set(key: string, value: string | object) {
await redis.set(key, JSON.stringify(value));
}
export async function get(key: string) {
const value: any = await redis.get(key);
return JSON.parse(value);
}
export async function clearAllKeys() {
// Retrieve all keys matching the pattern '*'
const keys = await redis.keys("user:*");
// If there are keys, delete them
if (keys.length > 0) {
console.log('keys: ', keys)
await redis.del(...keys);
if (typeof value == "object") await redis.set(key, JSON.stringify(value));
else {
await redis.set(key, value);
}
}
export async function getSimple(key: string) {
const value: any = await redis.get(key);
return value;
}
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 '*'
const del_keys = await redis.keys(key);
// If there are keys, delete them
if (del_keys.length > 0) {
console.log("del_keys: ", del_keys);
await redis.del(...del_keys);
}
}
}
export async function findByContain(
key: string,
@ -54,7 +91,7 @@ export async function findByContain(
results.push(obj);
}
}
}
}
return results;
}
@ -62,7 +99,8 @@ export async function createObject({
whatsappId,
contactId,
identifier,
value
value,
history = ""
}: WhatsappData) {
const key = `whatsappId:${whatsappId}:contactId:${contactId}:identifier:${identifier}`;
const result = await redis.hmset(
@ -74,7 +112,9 @@ export async function createObject({
"identifier",
identifier,
"value",
value
value,
"history",
history
);
await redis.expire(key, 300);
@ -102,7 +142,8 @@ export async function findObject(
"whatsappId",
"contactId",
"identifier",
"value"
"value",
"history"
);
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
fromMe: boolean;
@Default(false)
@Column
fromAgent: boolean;
@Column(DataType.TEXT)
body: string;

View File

@ -23,7 +23,11 @@ import fs from "fs";
import dir from "path";
import { getSettingValue } from "./helpers/WhaticketSettings";
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, () => {
logger.info(`Server started on port: ${process.env.PORT}`);
@ -39,32 +43,59 @@ const server = app.listen(process.env.PORT, () => {
initIO(server);
// StartAllWhatsAppsSessions();
gracefulShutdown(server);
gracefulShutdown(server);
(async () => {
console.log("os.tmpdir(): ", os.tmpdir());
await clearAllKeys();
await clearAllKeys("user:*", "whatsapp:*", "queue:*");
const users = await User.findAll();
for (const user of users) {
const { id, name } = user;
if (name == "botqueue") {
const userService = await ShowUserService(id);
await setBotInfo(userService);
}
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();
let whatsapps: any = await Whatsapp.findAll({
attributes: ["id", "url", "phoneNumberId"]
attributes: ["id", "url", "phoneNumberId", "number", "greetingMessage"]
});
if (whatsapps && whatsapps.length > 0) {
for (let i = 0; i < whatsapps.length; i++) {
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(
`API URL: ${whatsapps[i].dataValues.url}/api/connection/status`

View File

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

View File

@ -1,6 +1,7 @@
import * as Yup from "yup";
import AppError from "../../errors/AppError";
import Queue from "../../models/Queue";
import { set } from "../../helpers/RedisClient";
interface QueueData {
name: string;
@ -9,68 +10,67 @@ interface QueueData {
}
const CreateQueueService = async (queueData: QueueData): Promise<Queue> => {
try {
const { color, name } = queueData;
const queueSchema = Yup.object().shape({
name: Yup.string()
.min(2, "ERR_QUEUE_INVALID_NAME")
.required("ERR_QUEUE_INVALID_NAME")
.test(
"Check-unique-name",
"ERR_QUEUE_NAME_ALREADY_EXISTS",
async value => {
if (value) {
const queueWithSameName = await Queue.findOne({
where: { name: value }
});
const queueSchema = Yup.object().shape({
name: Yup.string()
.min(2, "ERR_QUEUE_INVALID_NAME")
.required("ERR_QUEUE_INVALID_NAME")
.test(
"Check-unique-name",
"ERR_QUEUE_NAME_ALREADY_EXISTS",
async value => {
if (value) {
const queueWithSameName = await Queue.findOne({
where: { name: value }
});
return !queueWithSameName;
return !queueWithSameName;
}
return false;
}
),
color: Yup.string()
.required("ERR_QUEUE_INVALID_COLOR")
.test("Check-color", "ERR_QUEUE_INVALID_COLOR", async value => {
if (value) {
const colorTestRegex = /^#[0-9a-f]{3,6}$/i;
return colorTestRegex.test(value);
}
return false;
}
),
color: Yup.string()
.required("ERR_QUEUE_INVALID_COLOR")
.test("Check-color", "ERR_QUEUE_INVALID_COLOR", async value => {
if (value) {
const colorTestRegex = /^#[0-9a-f]{3,6}$/i;
return colorTestRegex.test(value);
}
return false;
})
.test(
"Check-color-exists",
"ERR_QUEUE_COLOR_ALREADY_EXISTS",
async value => {
if (value) {
const queueWithSameColor = await Queue.findOne({
where: { color: value }
});
return !queueWithSameColor;
})
.test(
"Check-color-exists",
"ERR_QUEUE_COLOR_ALREADY_EXISTS",
async value => {
if (value) {
const queueWithSameColor = await Queue.findOne({
where: { color: value }
});
return !queueWithSameColor;
}
return false;
}
return false;
}
)
});
)
});
try {
await queueSchema.validate({ color, name });
} catch (err: any) {
throw new AppError(err.message);
}
try {
await queueSchema.validate({ color, name });
} catch (err: any) {
throw new AppError(err.message);
}
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) {
console.error('===> Error on CreateQueueService.ts file: \n', error)
console.error("===> Error on CreateQueueService.ts file: \n", error);
throw new AppError(error.message);
}
};
export default CreateQueueService;

View File

@ -3,6 +3,7 @@ import * as Yup from "yup";
import AppError from "../../errors/AppError";
import Queue from "../../models/Queue";
import ShowQueueService from "./ShowQueueService";
import { set } from "../../helpers/RedisClient"
interface QueueData {
name?: string;
@ -14,9 +15,7 @@ const UpdateQueueService = async (
queueId: number | string,
queueData: QueueData
): Promise<Queue> => {
try {
const { color, name } = queueData;
const queueSchema = Yup.object().shape({
@ -30,7 +29,7 @@ const UpdateQueueService = async (
const queueWithSameName = await Queue.findOne({
where: { name: value, id: { [Op.not]: queueId } }
});
return !queueWithSameName;
}
return true;
@ -59,24 +58,25 @@ const UpdateQueueService = async (
}
)
});
try {
await queueSchema.validate({ color, name });
} catch (err: any) {
throw new AppError(err.message);
}
const queue = await ShowQueueService(queueId);
await queue.update(queueData);
// const { id, greetingMessage } = queue;
// await set(`queue:${id}`, { id, name, greetingMessage });
return queue;
} 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);
}
}
};
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
@ -102,12 +103,13 @@ const FindOrCreateTicketServiceBot = async (
}
ticket = await Ticket.create({
contactId: groupContact ? groupContact.id : contact.id,
status: status,
userId: botInfo.userIdBot,
isGroup: !!groupContact,
unreadMessages,
whatsappId
contactId: groupContact ? groupContact.id : contact.id,
status: status,
userId: botInfo.userIdBot,
isGroup: !!groupContact,
unreadMessages,
whatsappId,
phoneNumberId
});
console.log('yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy')

View File

@ -7,14 +7,17 @@ import Queue from "../../models/Queue";
import Message from "../../models/Message";
import { userInfo } from "os";
import { Op, where } from "sequelize";
import { Op, QueryTypes, where } from "sequelize";
import { Sequelize } from "sequelize";
import moment from "moment";
const dbConfig = require("../../config/database");
const sequelize = new Sequelize(dbConfig);
import { startOfDay, endOfDay, parseISO, getDate } from "date-fns";
import { string } from "yup/lib/locale";
import Whatsapp from "../../models/Whatsapp";
import Query from "mysql2/typings/mysql/lib/protocol/sequences/Query"
interface Request {
userId: string | number;
@ -41,43 +44,41 @@ const ShowTicketReport = async ({
queueId
}: Request): Promise<Response> => {
let where_clause: any = {};
// let where_clause_msg: any = {};
let query = "";
if (userId !== "0") {
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) {
where_clause.queueId = queueId;
query = `AND t.queueId = ${queueId}`;
}
const limit = 40;
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({
where: where_clause,
where: {
id: { [Op.in]: _ticketsId.map((t: any) => t.id) }
},
limit,
offset,
@ -108,7 +109,6 @@ const ShowTicketReport = async ({
model: Message,
required: true,
separate: true,
where: where_clause_msg ,
attributes: [
"body",
@ -143,10 +143,10 @@ const ShowTicketReport = async ({
model: Whatsapp,
attributes: ["name"]
}
],
],
order: [["updatedAt", "DESC"]]
});
const hasMore = count > offset + tickets.length;
if (!tickets) {

View File

@ -1,27 +1,60 @@
import axios from "axios";
import AppError from "../../errors/AppError";
import endPointQuery from "../../helpers/EndPointQuery";
import GetDefaultWhatsApp from "../../helpers/GetDefaultWhatsApp";
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;
const wbot_url = await getWbot(defaultWhatsapp.id);
if (defaultWhatsapp) {
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;
// console.log('isValidNumber.data.number: ', isValidNumber.data.number)
if (data?.isValid) {
isValidNumber = data;
}
}
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");
}
if (isValidNumber && isValidNumber?.isValid) return isValidNumber.number;
} catch (err: any) {
if (err.message === "invalidNumber") {
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");
}
if (isValidNumber && isValidNumber.data.isValid)
return isValidNumber.data.number
};
export default CheckIsValidContact;

View File

@ -1,23 +1,47 @@
import axios from "axios";
import endPointQuery from "../../helpers/EndPointQuery";
import GetDefaultWhatsApp from "../../helpers/GetDefaultWhatsApp";
import { getWbot } from "../../libs/wbot";
const GetProfilePicUrl = async (number: string): Promise<any> => {
const defaultWhatsapp = await GetDefaultWhatsApp({
ignoreNoWhatsappFound: true
});
let profilePicUrl;
const defaultWhatsapp = await GetDefaultWhatsApp({});
if (defaultWhatsapp) {
const wbot_url = await getWbot(defaultWhatsapp.id);
const wbot_url = await getWbot(defaultWhatsapp.id);
const {data} = 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)
if (profilePicUrl && profilePicUrl.data.data) {
return profilePicUrl.data.data;
if (data?.data) {
profilePicUrl = data.data;
}
}
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
return null;
};
export default GetProfilePicUrl;

View File

@ -92,13 +92,14 @@ import {
createObject,
findByContain,
findObject,
get
get,
getSimple
} from "../../helpers/RedisClient";
import FindOrCreateTicketServiceBot from "../TicketServices/FindOrCreateTicketServiceBot";
import ShowTicketService from "../TicketServices/ShowTicketService";
import ShowQueuesByUser from "../UserServices/ShowQueuesByUser";
import ListWhatsappQueuesByUserQueue from "../UserServices/ListWhatsappQueuesByUserQueue";
import CreateContactService from "../ContactServices/CreateContactService"
import CreateContactService from "../ContactServices/CreateContactService";
var lst: any[] = getWhatsappIds();
@ -175,9 +176,14 @@ const verifyMediaMessage = async (
mediaUrl: media.filename,
mediaType: media.mimetype.split("/")[0],
quotedMsgId: quotedMsg,
phoneNumberId: msg?.phoneNumberId
phoneNumberId: msg?.phoneNumberId,
fromAgent: false
};
if (msg?.fromMe) {
messageData = { ...messageData, fromAgent: true };
}
if (!ticket?.phoneNumberId) {
if (!media.filename) {
const ext = media.mimetype.split("/")[1].split(";")[0];
@ -280,18 +286,33 @@ const verifyMessage = async (
contact: Contact,
quotedMsg?: any
) => {
const messageData = {
let messageData = {
id: msg.id.id,
ticketId: ticket.id,
contactId: msg.fromMe ? undefined : contact.id,
body: msg.body,
fromMe: msg.fromMe,
fromAgent: false,
mediaType: msg.type,
read: msg.fromMe,
quotedMsgId: quotedMsg,
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 CreateMessageService({ messageData });
@ -318,13 +339,14 @@ const verifyQueue = async (
selectedOption = 1;
choosenQueue = queues[+selectedOption - 1];
} else {
selectedOption = msg.body;
selectedOption = msg?.body;
//////////////// EXTRAIR APENAS O NÚMERO ///////////////////
selectedOption = selectedOption.replace(/[^1-9]/g, "");
///////////////////////////////////
choosenQueue = queues[+selectedOption - 1];
if (selectedOption && selectedOption.trim().length > 0) {
//////////////// EXTRAIR APENAS O NÚMERO ///////////////////
selectedOption = selectedOption.replace(/[^1-9]/g, "");
///////////////////////////////////
choosenQueue = queues[+selectedOption - 1];
}
}
if (choosenQueue) {
@ -348,13 +370,14 @@ const verifyQueue = async (
ticketId: ticket.id
});
const data = await get("ura");
const data = await get({ key: "ura", parse: true });
await createObject({
whatsappId: `${ticket.whatsappId}`,
contactId: `${ticket.contactId}`,
identifier: "ura",
value: data[1].id
value: data[1].id,
history: `|${data[1].id}`
});
botSendMessage(ticket, data[1].value);
@ -505,9 +528,7 @@ const transferTicket = async (
ticket: Ticket,
sendGreetingMessage?: boolean
) => {
const botInfo = await BotIsOnQueue("botqueue");
console.log("kkkkkkkkkkkkkkkkkkkkk queueName: ", queueName);
const botInfo = await BotIsOnQueue("botqueue");
const queuesWhatsGreetingMessage = await queuesOutBot(
wbot,
@ -610,7 +631,7 @@ const handleMessage = async (
return;
}
}
}
if (!isValidMsg(msg)) {
return;
@ -780,33 +801,33 @@ const handleMessage = async (
await verifyQueue(wbot, msg, ticket, contact);
}
if (msg.type === "vcard") {
try {
const array = msg.body.split("\n");
const obj = [];
let contact = "";
for (let index = 0; index < array.length; index++) {
const v = array[index];
const values = v.split(":");
for (let ind = 0; ind < values.length; ind++) {
if (values[ind].indexOf("+") !== -1) {
obj.push({ number: values[ind] });
}
if (values[ind].indexOf("FN") !== -1) {
contact = values[ind + 1];
}
if (msg.type === "vcard") {
try {
const array = msg.body.split("\n");
const obj = [];
let contact = "";
for (let index = 0; index < array.length; index++) {
const v = array[index];
const values = v.split(":");
for (let ind = 0; ind < values.length; ind++) {
if (values[ind].indexOf("+") !== -1) {
obj.push({ number: values[ind] });
}
if (values[ind].indexOf("FN") !== -1) {
contact = values[ind + 1];
}
}
for await (const ob of obj) {
const cont = await CreateContactService({
name: contact,
number: ob.number.replace(/\D/g, "")
});
}
} catch (error) {
console.log(error);
}
for await (const ob of obj) {
const cont = await CreateContactService({
name: contact,
number: ob.number.replace(/\D/g, "")
});
}
} catch (error) {
console.log(error);
}
}
const botInfo = await BotIsOnQueue("botqueue");
@ -820,7 +841,7 @@ const handleMessage = async (
ticket.status == "pending" ||
ticket.status == "queueChoice")
) {
const filteredUsers = await findByContain("user:*", "name", msg?.body);
const filteredUsers = await findByContain("user:*", "name", msg?.body);
if (filteredUsers && filteredUsers.length > 0) {
if (botInfo.isOnQueue) {
@ -964,7 +985,7 @@ const handleMessage = async (
const menu = async (userTyped: string, whatsappId: any, contactId: any) => {
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]);
@ -973,7 +994,8 @@ const menu = async (userTyped: string, whatsappId: any, contactId: any) => {
whatsappId,
contactId,
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 (
lastId &&
lastId.length == 4 &&
(lastId.length == 4 || lastId.length == 5) &&
lastId[3] &&
lastId[3].trim().length > 0
) {
@ -993,23 +1015,49 @@ const menu = async (userTyped: string, whatsappId: any, contactId: any) => {
o.value.toLowerCase() == userTyped.toLowerCase()
);
// TEST DEL
console.log("OPTION: ", option);
if (!option && userTyped != "0") {
if (!option && userTyped != "0" && userTyped != "#") {
if (!existSubMenu()) {
const response = await mainOptionsMenu(userTyped);
if (response) return response;
else {
console.log("kkkkkkkkkkkkkkkkkkk");
await createObject({
let uraOptionSelected = await findObject(
whatsappId,
contactId,
identifier: "ura",
value: data[1].id
});
"ura"
);
uraOptionSelected = uraOptionSelected[4].split("|");
return data[1];
if (uraOptionSelected.length == 1) {
await createObject({
whatsappId,
contactId,
identifier: "ura",
value: data[1].id,
history: `|${data[1].id}`
});
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) {
let response: any = data.find((o: any) => o.idmaster == option.id);
console.log(" RESPONSE OPTION: ", response, " | OPTION: ", option);
console.log(
"RRRRRRRRRRRRRRRRRRRRRRRRRRRRR response: ",
response,
" | option: ",
option
);
let history: any = await historyUra(whatsappId, contactId, response.id);
await createObject({
whatsappId,
contactId,
identifier: "ura",
value: response.id
value: response.id,
history
});
return response;
@ -1038,26 +1083,42 @@ const menu = async (userTyped: string, whatsappId: any, contactId: any) => {
whatsappId,
contactId,
identifier: "ura",
value: data[1].id
value: data[1].id,
history: `|${data[1].id}`
});
return data[1];
} else {
console.log("INVALID SEARCH");
} else if (userTyped == "#") {
let uraOptionSelected = await findObject(whatsappId, contactId, "ura");
let response = await existSubMenu();
if (response) return response;
uraOptionSelected = uraOptionSelected[4].split("|").filter(Boolean);
return {
value: data.find((o: any) => o.id == lastId[3])?.value
};
let id = uraOptionSelected[0];
// return {
// value: `Você digitou uma opçao inválida!\n\n${
// data.find((o: any) => o.id == lastId[3])?.value
// }\n\nDigite 0 para voltar ao menu `
// };
}
let history = `|${uraOptionSelected[0]}`;
if (uraOptionSelected.length > 1) {
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;
}
}
function existSubMenu() {
@ -1069,18 +1130,29 @@ const menu = async (userTyped: string, whatsappId: any, contactId: 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(
(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) {
let response = data.find((o: any) => o.idmaster == menuOption.id);
if (response) {
let history = await historyUra(whatsappId, contactId, response.id);
await createObject({
whatsappId,
contactId,
identifier: "ura",
value: response.id
value: response.id,
history
});
return response;
@ -1189,6 +1261,31 @@ export {
mediaTypeWhatsappOfficial,
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) {
return await Whatsapp.findByPk(whatsappId);
}

View File

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

@ -87,7 +87,7 @@ const WhatsAppModal = ({ open, onClose, whatsAppId, whatsAppOfficial }) => {
if (!whatsAppId) return
try {
const { data } = await api.get(`whatsapp/${whatsAppId}`)
const { data } = await api.get(`whatsapp/${whatsAppId}`)
setWhatsApp(data)
setIsOfficial(data?.isOfficial)

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 api from "../../services/api"
import SelectField from "../../components/Report/SelectField"
@ -17,6 +17,8 @@ import Checkbox from '@mui/material/Checkbox'
import { Button } from "@material-ui/core"
import ReportModal from "../../components/ReportModal"
import ReportModalType from "../../components/ReportModalType"
import MaterialTable from 'material-table'
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 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) => {
@ -276,21 +281,16 @@ const Report = () => {
const [hasMore, setHasMore] = useState(false)
const [pageNumberTickets, setTicketsPageNumber] = useState(1)
const [totalCountTickets, setTotalCountTickets] = useState(0)
const [pageNumber, setPageNumber] = useState(1)
const [users, dispatch] = useReducer(reducer, [])
const [startDate, setDatePicker1] = useState(new Date())
const [endDate, setDatePicker2] = useState(new Date())
const [userId, setUser] = useState(null)
const [query, dispatchQ] = useReducer(reducerQ, [])
const [reportOption, setReport] = useState('1')
const [reporList,] = useState(report)
const [profile, setProfile] = useState('')
const [dataRows, setData] = useState([])
const [onQueueStatus, setOnQueueProcessStatus] = useState(undefined)
const [csvFile, setCsvFile] = useState()
const [selectedValue, setSelectedValue] = useState('created')
@ -298,6 +298,11 @@ const Report = () => {
const [queues, setQueues] = useState([])
const [queueId, setQueue] = useState(null)
const [reportTypeList,] = useState(reportOptType)
const [reportType, setReportType] = useState('1')
const [firstLoad, setFirstLoad] = useState(true);
useEffect(() => {
dispatch({ type: "RESET" })
dispatchQ({ type: "RESET" })
@ -306,6 +311,14 @@ const Report = () => {
}, [searchParam, profile])
useEffect(() => {
if (firstLoad) {
setFirstLoad(false)
} else {
}
}, [firstLoad]);
useEffect(() => {
//setLoading(true);
@ -337,16 +350,14 @@ const Report = () => {
useEffect(() => {
//setLoading(true);
if (firstLoad) return
const delayDebounceFn = setTimeout(() => {
const delayDebounceFn = setTimeout(() => {
setLoading(true)
const fetchQueries = async () => {
try {
if (reportOption === '1') {
// const { data } = await api.get("/reports/", { params: { userId: userId ? userId : 0, startDate: convertAndFormatDate(startDate), endDate: convertAndFormatDate(endDate), pageNumber: pageNumberTickets }, })
if (reportOption === '1') {
const { data } = await api.get("/reports/", { params: { userId, startDate, endDate, pageNumber: pageNumberTickets, createdOrUpdated: selectedValue, queueId }, userQueues: userA.queues })
let ticketsQueue = data.tickets
@ -424,8 +435,21 @@ const Report = () => {
setChecked(true)
}
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(() => {
if (reportOption === '1') {
@ -500,7 +524,7 @@ const Report = () => {
const handleCSVMessages = () => {
const handleCSVMessages = (type = 'default') => {
const fetchQueries = async () => {
@ -519,7 +543,8 @@ const Report = () => {
userId: userId,
startDate: startDate,
endDate: endDate
}
},
query_type: type
})
const onQueueStatus = querySavedOnQueue.data.queueStatus
@ -639,7 +664,10 @@ const Report = () => {
case 'empty':
return (
<>
<Button
{query && query.length > 0 &&
<ReportModalType currencies={reportTypeList} func={reportTypeValue} reportOption={reportType} />
}
{/* <Button
disabled={query && query.length > 0 ? false : true}
variant="contained"
color="primary"
@ -648,7 +676,8 @@ const Report = () => {
}}
>
{"CSV ALL"}
</Button>
</Button> */}
</>)
case 'pending' || 'processing':