commit
d1ceb54590
|
@ -10,7 +10,7 @@ import User from "../models/User";
|
|||
import Queue from "../models/Queue";
|
||||
import UserOnlineTime from "../models/UserOnlineTime";
|
||||
|
||||
import { Op, Sequelize,literal } from "sequelize";
|
||||
import { Op, Sequelize, literal } from "sequelize";
|
||||
import format from 'date-fns/format';
|
||||
import ptBR from 'date-fns/locale/pt-BR';
|
||||
import { splitDateTime } from "../helpers/SplitDateTime";
|
||||
|
@ -19,12 +19,19 @@ import ListUserParamiterService from "../services/UserServices/ListUserParamiter
|
|||
|
||||
import ShowUserServiceReport from "../services/UserServices/ShowUserServiceReport";
|
||||
|
||||
import CountTicketsByUserQueue from "../services/UserServices/CountTicketsByUserQueue";
|
||||
|
||||
import ShowQueuesByUser from "../services/UserServices/ShowQueuesByUser";
|
||||
import { filter } from "bluebird";
|
||||
|
||||
|
||||
|
||||
type IndexQuery = {
|
||||
userId: string;
|
||||
startDate: string;
|
||||
endDate: string;
|
||||
};
|
||||
pageNumber: string;
|
||||
};
|
||||
|
||||
|
||||
export const reportUserByDateStartDateEnd = async (req: Request, res: Response): Promise<Response> => {
|
||||
|
@ -33,17 +40,21 @@ export const reportUserByDateStartDateEnd = async (req: Request, res: Response):
|
|||
throw new AppError("ERR_NO_PERMISSION", 403);
|
||||
}
|
||||
|
||||
const { userId, startDate, endDate } = req.query as IndexQuery
|
||||
const { userId, startDate, endDate, pageNumber } = req.query as IndexQuery
|
||||
|
||||
|
||||
const data_query = await ShowTicketReport(userId, startDate, endDate);
|
||||
console.log('PAGE NUMBER: ', pageNumber)
|
||||
|
||||
return res.status(200).json(data_query);
|
||||
|
||||
const { tickets, count, hasMore } = await ShowTicketReport({ userId, startDate, endDate, pageNumber });
|
||||
|
||||
// return res.status(200).json(data_query);
|
||||
|
||||
return res.status(200).json({ tickets, count, hasMore });
|
||||
};
|
||||
|
||||
|
||||
export const reportUserService= async (req: Request, res: Response): Promise<Response> => {
|
||||
export const reportUserService = async (req: Request, res: Response): Promise<Response> => {
|
||||
|
||||
if (req.user.profile !== "master" && req.user.profile !== "admin") {
|
||||
throw new AppError("ERR_NO_PERMISSION", 403);
|
||||
|
@ -51,49 +62,153 @@ export const reportUserService= async (req: Request, res: Response): Promise<Res
|
|||
const { userId, startDate, endDate } = req.query as IndexQuery
|
||||
|
||||
|
||||
let usersProfile = await ListUserParamiterService({profile: 'user'})
|
||||
let usersProfile = await ListUserParamiterService({ profile: 'user' })
|
||||
|
||||
const sumUserOlineTime = await ShowUserServiceReport({startDate, endDate, userId});
|
||||
const closedByUser = await ShowUserServiceReport({startDate, endDate, ticketStatus: 'closed', userId});
|
||||
const openByUser = await ShowUserServiceReport({startDate, endDate, ticketStatus: 'open', userId});
|
||||
const sumUserOlineTime = await ShowUserServiceReport({ startDate, endDate, userId });
|
||||
const closedByUser = await ShowUserServiceReport({ startDate, endDate, ticketStatus: 'closed', userId });
|
||||
const openByUser = await ShowUserServiceReport({ startDate, endDate, ticketStatus: 'open', userId });
|
||||
|
||||
let dateTime = splitDateTime(new Date(format(new Date(), 'yyyy-MM-dd HH:mm:ss', { locale: ptBR })))
|
||||
const onlineUsers = await ListUserOnlineOffline({ date: dateTime.fullDate })
|
||||
|
||||
const openByUserOnQueue = await CountTicketsByUserQueue({ startDate: startDate, endDate: endDate, status: 'open', clientChatStart: true })
|
||||
const openByUserOutQueue = await CountTicketsByUserQueue({ startDate: startDate, endDate: endDate, status: 'open', clientChatStart: false })
|
||||
|
||||
usersProfile.map((user:any) => {
|
||||
const closedByUserOnQueue = await CountTicketsByUserQueue({ startDate: startDate, endDate: endDate, status: 'closed', clientChatStart: true })
|
||||
const closedUserOutQueue = await CountTicketsByUserQueue({ startDate: startDate, endDate: endDate, status: 'closed', clientChatStart: false })
|
||||
|
||||
let index = sumUserOlineTime.findIndex((e:any) => e.userId == user.id)
|
||||
// let openQueueInOut = openByUserOnQueue.concat(openByUserOutQueue)
|
||||
// let closedQueueInOut = closedByUserOnQueue.concat(closedUserOutQueue)
|
||||
|
||||
|
||||
const queuesByUser = await ShowQueuesByUser({ profile: 'user' })
|
||||
|
||||
let openCloseOnQueue = openByUserOnQueue.concat(closedByUserOnQueue)
|
||||
let openCloseOutQueue = openByUserOutQueue.concat(closedUserOutQueue)
|
||||
|
||||
for (let i = 0; i < queuesByUser.length; i++) {
|
||||
|
||||
queuesByUser[i].countOpen = 0
|
||||
queuesByUser[i].countClosed = 0
|
||||
|
||||
for (let x = 0; x < openCloseOnQueue.length; x++) {
|
||||
if ((queuesByUser[i].userId == openCloseOnQueue[x].userId) &&
|
||||
(queuesByUser[i].queueId == openCloseOnQueue[x].queueId && openCloseOnQueue[x].status == 'open')) {
|
||||
queuesByUser[i].countOpen = openCloseOnQueue[x].totAttendance
|
||||
}
|
||||
else if ((queuesByUser[i].userId == openCloseOnQueue[x].userId) &&
|
||||
(queuesByUser[i].queueId == openCloseOnQueue[x].queueId && openCloseOnQueue[x].status == 'closed')) {
|
||||
queuesByUser[i].countClosed = openCloseOnQueue[x].totAttendance
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// console.log('queuesByUser: ', queuesByUser)
|
||||
|
||||
|
||||
|
||||
// console.log('queuesByUser: ',queuesByUser)
|
||||
// console.log()
|
||||
// console.log('CLIENT START TRUE openByUserOnQueue: ', openByUserOnQueue)
|
||||
// console.log()
|
||||
// console.log('CLIENT START FALSE openByUserOutQueue: ', openByUserOutQueue)
|
||||
// console.log()
|
||||
// console.log('CLIENT START TRUE closedByUserOnQueue: ', closedByUserOnQueue)
|
||||
// console.log()
|
||||
// console.log('CLIENT START FALSE closedUserOutQueue: ', closedUserOutQueue)
|
||||
|
||||
|
||||
usersProfile.map((user: any) => {
|
||||
|
||||
let index = sumUserOlineTime.findIndex((e: any) => e.userId == user.id)
|
||||
|
||||
if (index != -1) {
|
||||
user.sumOnlineTime = sumUserOlineTime[index];
|
||||
}
|
||||
|
||||
index = closedByUser.findIndex((e:any) => e.userId == user.id)
|
||||
index = closedByUser.findIndex((e: any) => e.userId == user.id)
|
||||
|
||||
if (index != -1) {
|
||||
user.sumClosed = closedByUser[index];
|
||||
}
|
||||
|
||||
index = openByUser.findIndex((e:any) => e.userId == user.id)
|
||||
index = openByUser.findIndex((e: any) => e.userId == user.id)
|
||||
|
||||
if (index != -1) {
|
||||
user.sumOpen = openByUser[index]
|
||||
}
|
||||
|
||||
|
||||
index = onlineUsers.findIndex((e:any) => e.userId == user.id)
|
||||
|
||||
|
||||
|
||||
// let openByUserOut = openQueueInOut.filter((e: any) => e.userId == user.id && !e.queueName)
|
||||
// let openByUserIn = openQueueInOut.filter((e: any) => e.userId == user.id && e.queueName)
|
||||
|
||||
// if (openByUserOut && openByUserOut.length > 0) {
|
||||
// user.openTicketByUserOut = openByUserOut
|
||||
// }
|
||||
// if (openByUserIn && openByUserIn.length > 0) {
|
||||
// user.openTicketByUserIn = openByUserIn
|
||||
// }
|
||||
|
||||
// let closedByUserOut = closedQueueInOut.filter((e: any) => e.userId == user.id && !e.queueName)
|
||||
// let closedByUserIn = closedQueueInOut.filter((e: any) => e.userId == user.id && e.queueName)
|
||||
|
||||
// if (closedByUserOut && closedByUserOut.length > 0) {
|
||||
// user.closedTicketByUserOut = closedByUserOut
|
||||
// }
|
||||
// if (closedByUserIn && closedByUserIn.length > 0) {
|
||||
// user.closedTicketByUserIn = closedByUserIn
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// OPEN, CLOSED TICKETS STARTED BY USERS
|
||||
let openClosedOutQueue = {}
|
||||
let open = openCloseOutQueue.filter((e) => e.userId == user.id && e.status == 'open')
|
||||
let closed = openCloseOutQueue.filter((e) => e.userId == user.id && e.status == 'closed')
|
||||
|
||||
openClosedOutQueue = {
|
||||
...openClosedOutQueue,
|
||||
userId: user.id,
|
||||
countOpen: open && open.length > 0 ? open[0].totAttendance : 0,
|
||||
countClosed: closed && closed.length > 0 ? closed[0].totAttendance : 0
|
||||
}
|
||||
|
||||
user.openClosedOutQueue = openClosedOutQueue
|
||||
|
||||
|
||||
// OPEN, CLOSED TICKETS STARTED BY CLIENTS
|
||||
let openClosedInQueue = queuesByUser.filter((e) => e.userId == user.id)
|
||||
|
||||
if (openClosedInQueue && openClosedInQueue.length > 0) {
|
||||
user.openClosedInQueue = openClosedInQueue
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
index = onlineUsers.findIndex((e: any) => e.userId == user.id)
|
||||
|
||||
if (index != -1) {
|
||||
user.statusOnline = onlineUsers[index]
|
||||
}
|
||||
|
||||
if(startDate.length>0 && startDate.split('-').length == 3){
|
||||
if (startDate.length > 0 && startDate.split('-').length == 3) {
|
||||
let date = startDate.split('-')
|
||||
user.startDate = `${date[2]}/${date[1]}/${date[0]}`
|
||||
}
|
||||
|
||||
if(endDate.length>0 && endDate.split('-').length == 3){
|
||||
if (endDate.length > 0 && endDate.split('-').length == 3) {
|
||||
let date = endDate.split('-')
|
||||
user.endDate = `${date[2]}/${date[1]}/${date[0]}`
|
||||
}
|
||||
|
@ -124,4 +239,3 @@ export const reportMessagesUserByDateStartDateEnd = async (req: Request, res: Re
|
|||
|
||||
|
||||
|
||||
|
|
@ -21,6 +21,8 @@ import format from 'date-fns/format';
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
type IndexQuery = {
|
||||
searchParam: string;
|
||||
pageNumber: string;
|
||||
|
@ -44,8 +46,12 @@ import ListStatusChatEndService from "../services/StatusChatEndService/ListStatu
|
|||
import Ticket from "../models/Ticket";
|
||||
import ShowUserServiceReport from "../services/UserServices/ShowUserServiceReport";
|
||||
import TicketEmiterSumOpenClosedByUser from "../helpers/OnlineReporEmiterInfoByUser";
|
||||
import CountTicketService from "../services/TicketServices/CountTicketService";
|
||||
import CountTicketsByUserQueue from "../services/UserServices/CountTicketsByUserQueue";
|
||||
import ShowUserService from "../services/UserServices/ShowUserService";
|
||||
|
||||
export const index = async (req: Request, res: Response): Promise<Response> => {
|
||||
|
||||
const {
|
||||
pageNumber,
|
||||
status,
|
||||
|
@ -58,7 +64,6 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
|
|||
} = req.query as IndexQuery;
|
||||
|
||||
|
||||
|
||||
const userId = req.user.id;
|
||||
|
||||
let queueIds: number[] = [];
|
||||
|
@ -138,6 +143,17 @@ export const show = async (req: Request, res: Response): Promise<Response> => {
|
|||
};
|
||||
|
||||
|
||||
export const count = async (req: Request, res: Response): Promise<Response> => {
|
||||
|
||||
type indexQ = { status: string; date?: string; };
|
||||
const {status, date} = req.query as IndexQuery
|
||||
|
||||
const ticketCount = await CountTicketService(status, date);
|
||||
|
||||
return res.status(200).json(ticketCount);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -221,12 +237,15 @@ export const update = async (req: Request, res: Response): Promise<Response> =>
|
|||
ticketId
|
||||
});
|
||||
|
||||
const dateToday = splitDateTime(new Date(format(new Date(), 'yyyy-MM-dd HH:mm:ss', { locale: ptBR })))
|
||||
TicketEmiterSumOpenClosedByUser(ticketData.userId.toString(), dateToday.fullDate, dateToday.fullDate)
|
||||
|
||||
ticket2 = ticket
|
||||
|
||||
}
|
||||
|
||||
|
||||
// test del
|
||||
|
||||
|
||||
if (userOldInfo) {
|
||||
|
||||
|
@ -234,12 +253,15 @@ export const update = async (req: Request, res: Response): Promise<Response> =>
|
|||
|
||||
if (userOldInfo.userId) {
|
||||
|
||||
// console.log('FECHOU...')
|
||||
|
||||
TicketEmiterSumOpenClosedByUser(userOldInfo.userId.toString(), dateToday.fullDate, dateToday.fullDate)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
|
||||
return res.status(200).json(ticket2);
|
||||
};
|
||||
|
@ -248,7 +270,6 @@ export const update = async (req: Request, res: Response): Promise<Response> =>
|
|||
|
||||
|
||||
|
||||
|
||||
// export const update = async (
|
||||
// req: Request,
|
||||
// res: Response
|
||||
|
|
|
@ -6,7 +6,7 @@ module.exports = {
|
|||
"StatusChatEnds",
|
||||
[
|
||||
{
|
||||
name: "SEM RETORNO DO CLIENTE",
|
||||
name: "FINALIZADO",
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date()
|
||||
},
|
||||
|
|
|
@ -3,14 +3,64 @@ import { splitDateTime } from "../helpers/SplitDateTime";
|
|||
import format from 'date-fns/format';
|
||||
import ShowUserServiceReport from '../services/UserServices/ShowUserServiceReport';
|
||||
import { getIO } from "../libs/socket";
|
||||
import CountTicketsByUserQueue from "../services/UserServices/CountTicketsByUserQueue";
|
||||
import ShowQueuesByUser from '../services/UserServices/ShowQueuesByUser';
|
||||
|
||||
// import CountTicketsByUserQueue from "../services/UserServices/CountTicketsByUserQueue";
|
||||
|
||||
|
||||
const TicketEmiterSumOpenClosedByUser = async (userId: string, startDate: string, endDate: string) => {
|
||||
|
||||
const openByUser: any[] = await ShowUserServiceReport({ startDate: startDate, endDate:endDate, ticketStatus: 'open', userId: userId.toString() });
|
||||
const closedByUser: any[] = await ShowUserServiceReport({ startDate: endDate, endDate:endDate, ticketStatus: 'closed', userId: userId.toString() });
|
||||
const openByUser: any[] = await ShowUserServiceReport({ startDate: startDate, endDate: endDate, ticketStatus: 'open', userId: userId.toString() });
|
||||
const closedByUser: any[] = await ShowUserServiceReport({ startDate: endDate, endDate: endDate, ticketStatus: 'closed', userId: userId.toString() });
|
||||
|
||||
|
||||
const openByUserOnQueue: any[] = await CountTicketsByUserQueue({ startDate: startDate, endDate: endDate, status: 'open', clientChatStart: true, userId: userId })
|
||||
const openByUserOutQueue: any[] = await CountTicketsByUserQueue({ startDate: startDate, endDate: endDate, status: 'open', clientChatStart: false, userId: userId })
|
||||
|
||||
const closedByUserOnQueue: any[] = await CountTicketsByUserQueue({ startDate: startDate, endDate: endDate, status: 'closed', clientChatStart: true, userId: userId })
|
||||
const closedUserOutQueue: any[] = await CountTicketsByUserQueue({ startDate: startDate, endDate: endDate, status: 'closed', clientChatStart: false, userId: userId })
|
||||
|
||||
|
||||
|
||||
const queuesByUser = await ShowQueuesByUser({ profile: 'user', userId: userId })
|
||||
|
||||
let openCloseOnQueue = openByUserOnQueue.concat(closedByUserOnQueue)
|
||||
let openCloseOutQueue = openByUserOutQueue.concat(closedUserOutQueue)
|
||||
|
||||
|
||||
// OPEN, CLOSED TICKETS STARTED BY CLIENTS
|
||||
for (let i = 0; i < queuesByUser.length; i++) {
|
||||
|
||||
queuesByUser[i].countOpen = 0
|
||||
queuesByUser[i].countClosed = 0
|
||||
|
||||
for (let x = 0; x < openCloseOnQueue.length; x++) {
|
||||
if ((queuesByUser[i].userId == openCloseOnQueue[x].userId) &&
|
||||
(queuesByUser[i].queueId == openCloseOnQueue[x].queueId && openCloseOnQueue[x].status == 'open')) {
|
||||
queuesByUser[i].countOpen = openCloseOnQueue[x].totAttendance
|
||||
}
|
||||
else if ((queuesByUser[i].userId == openCloseOnQueue[x].userId) &&
|
||||
(queuesByUser[i].queueId == openCloseOnQueue[x].queueId && openCloseOnQueue[x].status == 'closed')) {
|
||||
queuesByUser[i].countClosed = openCloseOnQueue[x].totAttendance
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// OPEN, CLOSED TICKETS STARTED BY USERS
|
||||
let openClosedOutQueue = {}
|
||||
let open = openCloseOutQueue.filter((e) => e.status == 'open')
|
||||
let closed = openCloseOutQueue.filter((e) => e.status == 'closed')
|
||||
|
||||
openClosedOutQueue = {
|
||||
...openClosedOutQueue,
|
||||
userId: userId,
|
||||
countOpen: open && open.length > 0 ? open[0].totAttendance : 0,
|
||||
countClosed: closed && closed.length > 0 ? closed[0].totAttendance : 0
|
||||
}
|
||||
|
||||
//openByUser : [ { id: 13, status: 'online' } ]
|
||||
|
||||
const io = getIO();
|
||||
io.emit("onlineStatus", {
|
||||
|
@ -18,9 +68,15 @@ const TicketEmiterSumOpenClosedByUser = async (userId: string, startDate: string
|
|||
userOnlineTime: {
|
||||
sumOpen: openByUser.length > 0 ? openByUser[0] : { userId: userId, count: '' },
|
||||
sumClosed: closedByUser.length > 0 ? closedByUser[0] : { userId: userId, count: '' },
|
||||
|
||||
openClosedOutQueue: openClosedOutQueue,
|
||||
openClosedInQueue: queuesByUser
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
};
|
||||
|
||||
export default TicketEmiterSumOpenClosedByUser
|
|
@ -13,6 +13,8 @@ const fastFolderSize = require('fast-folder-size')
|
|||
const { promisify } = require('util')
|
||||
const fs = require('fs')
|
||||
|
||||
const { exec } = require("child_process");
|
||||
|
||||
let scheduler_monitor: any;
|
||||
let timeInterval = 5
|
||||
|
||||
|
@ -53,6 +55,35 @@ const monitor = async () => {
|
|||
}
|
||||
|
||||
|
||||
exec("df -h /", (error: any, stdout: any, stderr: any) => {
|
||||
|
||||
if (error) {
|
||||
console.log(`exec error: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
if (stderr) {
|
||||
console.log(`exec stderr: ${stderr}`);
|
||||
return;
|
||||
}
|
||||
|
||||
stdout = stdout.split(/\r?\n/)
|
||||
stdout = stdout[1].trim().split(/\s+/)
|
||||
|
||||
// DISK SPACE MONITORING
|
||||
const io = getIO();
|
||||
io.emit("diskSpaceMonit", {
|
||||
action: "update",
|
||||
diskSpace: {
|
||||
size: stdout[1],
|
||||
used: stdout[2],
|
||||
available: stdout[3],
|
||||
use: stdout[4]
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
// WHATS SESSION SIZE MONITORING
|
||||
const whatsapps = await ListWhatsAppsService();
|
||||
|
|
|
@ -67,7 +67,7 @@ export const initWbot = async (whatsapp: Whatsapp, backupSessionRestore: boolean
|
|||
// usando instancia do chrome
|
||||
const wbot: Session = new Client({
|
||||
session: sessionCfg, authStrategy: new LocalAuth({ clientId: 'bd_' + whatsapp.id }),
|
||||
puppeteer: { args: ['--no-sandbox', '--disable-setuid-sandbox'], executablePath: process.env.CHROME_BIN || '/usr/bin/google-chrome-stable' },
|
||||
puppeteer: { args: ['--no-sandbox', '--disable-setuid-sandbox'], executablePath: process.env.CHROME_BIN || undefined },
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@ import * as TicketController from "../controllers/TicketController";
|
|||
const ticketRoutes = express.Router();
|
||||
|
||||
|
||||
ticketRoutes.get("/tickets/count", isAuth, TicketController.count);
|
||||
|
||||
ticketRoutes.get("/tickets", isAuth, TicketController.index);
|
||||
|
||||
ticketRoutes.get("/tickets/:ticketId", isAuth, TicketController.show);
|
||||
|
|
|
@ -16,4 +16,4 @@ StartAllWhatsAppsSessions();
|
|||
gracefulShutdown(server);
|
||||
|
||||
startSchedulingMonitor(5000)
|
||||
startWhoIsOnlineMonitor(5000)
|
||||
startWhoIsOnlineMonitor(2000)
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
import Ticket from "../../models/Ticket";
|
||||
import AppError from "../../errors/AppError";
|
||||
import { Op, where } from "sequelize";
|
||||
import { Sequelize } from "sequelize";
|
||||
|
||||
import { format } from "date-fns";
|
||||
import ptBR from 'date-fns/locale/pt-BR';
|
||||
|
||||
import { splitDateTime } from "../../helpers/SplitDateTime";
|
||||
const dateToday = splitDateTime(new Date(format(new Date(), 'yyyy-MM-dd HH:mm:ss', { locale: ptBR })))
|
||||
|
||||
const CountTicketService = async (status: string, date?: string): Promise<any> => {
|
||||
|
||||
let where_clause = {}
|
||||
|
||||
if (date) {
|
||||
where_clause = {
|
||||
createdAt: {
|
||||
[Op.gte]: date + ' 00:00:00.000000',
|
||||
[Op.lte]: date + ' 23:59:59.999999'
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// where_clause = {
|
||||
// createdAt: {
|
||||
// [Op.gte]: dateToday.fullDate + ' 00:00:00.000000',
|
||||
// [Op.lte]: dateToday.fullDate + ' 23:59:59.999999'
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
where_clause = { ...where_clause, status: status }
|
||||
|
||||
const ticket = await Ticket.findAll({
|
||||
where: where_clause,
|
||||
raw: true,
|
||||
attributes: [[Sequelize.fn("COUNT", Sequelize.col("Ticket.status")), "count"]],
|
||||
});
|
||||
|
||||
|
||||
if (!ticket) {
|
||||
throw new AppError("ERR_NO_TICKET_FOUND", 404);
|
||||
}
|
||||
|
||||
return ticket[0];
|
||||
};
|
||||
|
||||
export default CountTicketService;
|
|
@ -54,6 +54,12 @@ const CreateTicketService = async ({
|
|||
|
||||
TicketEmiterSumOpenClosedByUser(userId.toString(), dateToday.fullDate, dateToday.fullDate)
|
||||
|
||||
const io = getIO();
|
||||
io.emit("ticketStatus", {
|
||||
action: "update",
|
||||
ticketStatus: {ticketId: ticket.id, status: ticket.status}
|
||||
});
|
||||
|
||||
|
||||
//
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ const ListTicketsService = async ({
|
|||
showAll,
|
||||
userId,
|
||||
withUnreadMessages,
|
||||
unlimited='false'
|
||||
unlimited = 'false'
|
||||
}: Request): Promise<Response> => {
|
||||
let whereCondition: Filterable["where"] = {
|
||||
[Op.or]: [{ userId }, { status: "pending" }],
|
||||
|
@ -47,6 +47,8 @@ const ListTicketsService = async ({
|
|||
};
|
||||
let includeCondition: Includeable[];
|
||||
|
||||
|
||||
|
||||
includeCondition = [
|
||||
{
|
||||
model: Contact,
|
||||
|
@ -65,20 +67,21 @@ const ListTicketsService = async ({
|
|||
}
|
||||
|
||||
if (status) {
|
||||
|
||||
whereCondition = { ...whereCondition, status };
|
||||
|
||||
// console.log('TEST unlimited: ', unlimited)
|
||||
|
||||
if (unlimited === 'true' && status !== 'pending') {
|
||||
|
||||
whereCondition = {
|
||||
...whereCondition,
|
||||
status
|
||||
};
|
||||
|
||||
// if (unlimited) {
|
||||
// whereCondition = {
|
||||
// ...whereCondition,
|
||||
// createdAt: {
|
||||
// [Op.gte]: dateToday.fullDate + ' 00:00:00.000000',
|
||||
// [Op.lte]: dateToday.fullDate + ' 23:59:59.999999'
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
createdAt: {
|
||||
[Op.gte]: dateToday.fullDate + ' 00:00:00.000000',
|
||||
[Op.lte]: dateToday.fullDate + ' 23:59:59.999999'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -92,11 +95,7 @@ const ListTicketsService = async ({
|
|||
as: "messages",
|
||||
attributes: ["id", "body"],
|
||||
where: {
|
||||
body: where(
|
||||
fn("LOWER", col("body")),
|
||||
"LIKE",
|
||||
`%${sanitizedSearchParam}%`
|
||||
)
|
||||
body: where(fn("LOWER", col("body")), "LIKE", `%${sanitizedSearchParam}%`)
|
||||
},
|
||||
required: false,
|
||||
duplicating: false
|
||||
|
@ -107,19 +106,13 @@ const ListTicketsService = async ({
|
|||
...whereCondition,
|
||||
[Op.or]: [
|
||||
{
|
||||
"$contact.name$": where(
|
||||
fn("LOWER", col("contact.name")),
|
||||
"LIKE",
|
||||
`%${sanitizedSearchParam}%`
|
||||
)
|
||||
"$contact.name$": where(fn("LOWER", col("contact.name")), "LIKE", `%${sanitizedSearchParam}%`)
|
||||
},
|
||||
|
||||
{ "$contact.number$": { [Op.like]: `%${sanitizedSearchParam}%` } },
|
||||
|
||||
{
|
||||
"$message.body$": where(
|
||||
fn("LOWER", col("body")),
|
||||
"LIKE",
|
||||
`%${sanitizedSearchParam}%`
|
||||
)
|
||||
"$message.body$": where(fn("LOWER", col("body")), "LIKE", `%${sanitizedSearchParam}%`)
|
||||
}
|
||||
]
|
||||
};
|
||||
|
|
|
@ -16,12 +16,31 @@ import { startOfDay, endOfDay, parseISO, getDate} from "date-fns";
|
|||
import { string } from "yup/lib/locale";
|
||||
import Whatsapp from "../../models/Whatsapp";
|
||||
|
||||
interface Request {
|
||||
userId: string | number;
|
||||
startDate: string;
|
||||
endDate: string;
|
||||
pageNumber?: string;
|
||||
}
|
||||
|
||||
|
||||
interface Response {
|
||||
tickets: Ticket[];
|
||||
count: number;
|
||||
hasMore: boolean;
|
||||
}
|
||||
|
||||
//Report by user, startDate, endDate
|
||||
const ShowTicketReport = async (id: string | number, startDate: string, endDate: string): Promise<Ticket[]> => {
|
||||
const ShowTicketReport = async ({
|
||||
userId,
|
||||
startDate,
|
||||
endDate,
|
||||
pageNumber = "1"
|
||||
}: Request): Promise<Response> => {
|
||||
|
||||
let where_clause = {}
|
||||
|
||||
if(id=='0'){
|
||||
if(userId=='0'){
|
||||
where_clause = {
|
||||
createdAt: {
|
||||
[Op.gte]: startDate+' 00:00:00.000000',
|
||||
|
@ -31,7 +50,7 @@ const ShowTicketReport = async (id: string | number, startDate: string, endDate:
|
|||
}
|
||||
else{
|
||||
where_clause = {
|
||||
userid: id,
|
||||
userid: userId,
|
||||
createdAt: {
|
||||
[Op.gte]: startDate+' 00:00:00.000000',
|
||||
[Op.lte]: endDate +' 23:59:59.999999'
|
||||
|
@ -40,11 +59,14 @@ const ShowTicketReport = async (id: string | number, startDate: string, endDate:
|
|||
}
|
||||
|
||||
|
||||
const limit = 40;
|
||||
const offset = limit * (+pageNumber - 1);
|
||||
|
||||
|
||||
const ticket = await Ticket.findAll({
|
||||
const {count, rows: tickets} = await Ticket.findAndCountAll({
|
||||
|
||||
where: where_clause ,
|
||||
limit,
|
||||
offset,
|
||||
//attributes: ['id', 'status', 'createdAt', 'updatedAt'],
|
||||
|
||||
attributes: ['id', 'status', 'statusChatEnd', [Sequelize.fn("DATE_FORMAT",Sequelize.col("Ticket.createdAt"),"%d/%m/%Y %H:%i:%s"),"createdAt"],
|
||||
|
@ -82,14 +104,20 @@ const ShowTicketReport = async (id: string | number, startDate: string, endDate:
|
|||
},
|
||||
],
|
||||
|
||||
order: [
|
||||
['id', 'ASC']
|
||||
]
|
||||
|
||||
});
|
||||
|
||||
const hasMore = count > offset + tickets.length;
|
||||
|
||||
if (!ticket) {
|
||||
|
||||
if (!tickets) {
|
||||
throw new AppError("ERR_NO_TICKET_FOUND", 404);
|
||||
}
|
||||
|
||||
return ticket;
|
||||
return {tickets, count, hasMore};
|
||||
};
|
||||
|
||||
export default ShowTicketReport;
|
||||
|
|
|
@ -61,7 +61,6 @@ const UpdateTicketService = async ({
|
|||
}
|
||||
|
||||
|
||||
|
||||
io.to(ticket.status)
|
||||
.to("notification")
|
||||
.to(ticketId.toString())
|
||||
|
@ -70,6 +69,13 @@ const UpdateTicketService = async ({
|
|||
ticket
|
||||
});
|
||||
|
||||
|
||||
io.emit("ticketStatus", {
|
||||
action: "update",
|
||||
ticketStatus: {ticketId: ticket.id, status: ticket.status}
|
||||
});
|
||||
|
||||
|
||||
return { ticket, oldStatus, oldUserId };
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
|
||||
import { Sequelize, } from "sequelize";
|
||||
|
||||
const dbConfig = require("../../config/database");
|
||||
const sequelize = new Sequelize(dbConfig);
|
||||
|
||||
const { QueryTypes } = require('sequelize');
|
||||
|
||||
interface Request {
|
||||
startDate: string;
|
||||
endDate: string;
|
||||
status: string;
|
||||
clientChatStart: boolean;
|
||||
userId?: string | number;
|
||||
}
|
||||
|
||||
const CountTicketsByUserQueue = async ({ startDate, endDate, status, clientChatStart, userId }: Request): Promise<any[]> => {
|
||||
|
||||
let usersQueueInfo = []
|
||||
|
||||
if (clientChatStart) {
|
||||
|
||||
if (userId) {
|
||||
// CONSULTANDO POR CONVERSAS INICIADAS PELO CLIENTE
|
||||
usersQueueInfo = await sequelize.query(`select Users.id as userId, Tickets.status, Queues.id as queueId, Queues.name as queueName, \
|
||||
(select count(id) from Tickets where userId = Users.id and Tickets.status = '${status}' and Tickets.queueId = Queues.id \
|
||||
and (date(Tickets.createdAt) BETWEEN '${startDate} 00:00:00.000000' AND '${endDate} 23:59:59.999999')) as totAttendance \
|
||||
from Tickets inner join Users inner join Queues on Tickets.queueId = Queues.id and Tickets.userId = Users.id and Tickets.status = '${status}' \
|
||||
and (date(Tickets.createdAt) BETWEEN '${startDate} 00:00:00.000000' AND '${endDate} 23:59:59.999999') and Users.id = '${userId}' group by Users.email, Queues.name;`, { type: QueryTypes.SELECT });
|
||||
|
||||
} else {
|
||||
|
||||
// CONSULTANDO POR CONVERSAS INICIADAS PELO CLIENTE
|
||||
usersQueueInfo = await sequelize.query(`select Users.id as userId, Tickets.status, Queues.id as queueId, Queues.name as queueName, \
|
||||
(select count(id) from Tickets where userId = Users.id and Tickets.status = '${status}' and Tickets.queueId = Queues.id \
|
||||
and (date(Tickets.createdAt) BETWEEN '${startDate} 00:00:00.000000' AND '${endDate} 23:59:59.999999')) as totAttendance \
|
||||
from Tickets inner join Users inner join Queues on Tickets.queueId = Queues.id and Tickets.userId = Users.id and Tickets.status = '${status}' \
|
||||
and (date(Tickets.createdAt) BETWEEN '${startDate} 00:00:00.000000' AND '${endDate} 23:59:59.999999') group by Users.email, Queues.name;`, { type: QueryTypes.SELECT });
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
if (userId) {
|
||||
// CONSULTANDO POR CONVERSAS INICIADAS PELO ATENDENTE
|
||||
usersQueueInfo = await sequelize.query(`select Users.id as userId, Tickets.status, \
|
||||
(select count(id) from Tickets where userId = Users.id and Tickets.status = '${status}' and Tickets.queueId is null \
|
||||
and (date(Tickets.createdAt) BETWEEN '${startDate} 00:00:00.000000' AND '${endDate} 23:59:59.999999')) as totAttendance \
|
||||
from Tickets inner join Users on \
|
||||
Tickets.queueId is null and Tickets.userId = Users.id and Tickets.status = '${status}' \
|
||||
and (date(Tickets.createdAt) BETWEEN '${startDate} 00:00:00.000000' AND '${endDate} 23:59:59.999999') and Users.id = '${userId}' group by Users.email;`, { type: QueryTypes.SELECT });
|
||||
}
|
||||
else {
|
||||
// CONSULTANDO POR CONVERSAS INICIADAS PELO ATENDENTE
|
||||
usersQueueInfo = await sequelize.query(`select Users.id as userId, Tickets.status, \
|
||||
(select count(id) from Tickets where userId = Users.id and Tickets.status = '${status}' and Tickets.queueId is null \
|
||||
and (date(Tickets.createdAt) BETWEEN '${startDate} 00:00:00.000000' AND '${endDate} 23:59:59.999999')) as totAttendance \
|
||||
from Tickets inner join Users on \
|
||||
Tickets.queueId is null and Tickets.userId = Users.id and Tickets.status = '${status}' \
|
||||
and (date(Tickets.createdAt) BETWEEN '${startDate} 00:00:00.000000' AND '${endDate} 23:59:59.999999') group by Users.email;`, { type: QueryTypes.SELECT });
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return usersQueueInfo;
|
||||
};
|
||||
|
||||
export default CountTicketsByUserQueue;
|
||||
|
||||
|
||||
|
||||
|
|
@ -118,6 +118,7 @@ const CreateOrUpdateUserOnlineTime = async ({
|
|||
console.log('UpdatedAt string: ', updatedAtString)
|
||||
//
|
||||
|
||||
|
||||
io.emit("onlineStatus", {
|
||||
action: "update",
|
||||
userOnlineTime: {
|
||||
|
|
|
@ -1,33 +1,35 @@
|
|||
|
||||
import { Op, Sequelize } from "sequelize";
|
||||
import Queue from "../../models/Queue";
|
||||
import User from "../../models/User";
|
||||
import UserQueue from "../../models/UserQueue";
|
||||
|
||||
interface Request {
|
||||
userId?: string | number;
|
||||
profile?: string;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const ListUser = async ({profile, userId}: Request): Promise<User[]> => {
|
||||
const ListUser = async ({ profile, userId }: Request): Promise<User[]> => {
|
||||
|
||||
let where_clause = {}
|
||||
|
||||
if(userId && profile){
|
||||
if (userId && profile) {
|
||||
where_clause = {
|
||||
[Op.and]: [
|
||||
{userId: userId},
|
||||
{profile: profile}
|
||||
{ userId: userId },
|
||||
{ profile: profile }
|
||||
]
|
||||
}
|
||||
}
|
||||
else if(userId){
|
||||
else if (userId) {
|
||||
where_clause = {
|
||||
[Op.and]: [
|
||||
{userId: userId},
|
||||
{ userId: userId },
|
||||
]
|
||||
}
|
||||
}
|
||||
else if(profile){
|
||||
else if (profile) {
|
||||
where_clause = {
|
||||
profile: profile
|
||||
}
|
||||
|
@ -36,9 +38,25 @@ const ListUser = async ({profile, userId}: Request): Promise<User[]> => {
|
|||
|
||||
const users = await User.findAll({
|
||||
where: where_clause,
|
||||
raw:true,
|
||||
raw: true,
|
||||
attributes: ['id', 'name', 'email'],
|
||||
|
||||
|
||||
// include: [
|
||||
// {
|
||||
// model: UserQueue,
|
||||
// separate: true,
|
||||
|
||||
// attributes: ['id',],
|
||||
|
||||
// order: [
|
||||
// ['createdAt', 'ASC']
|
||||
// ]
|
||||
// },
|
||||
// ],
|
||||
|
||||
|
||||
|
||||
order: [["id", "ASC"]],
|
||||
})
|
||||
|
||||
|
@ -51,4 +69,3 @@ export default ListUser;
|
|||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
|
||||
import { Sequelize, } from "sequelize";
|
||||
|
||||
const dbConfig = require("../../config/database");
|
||||
const sequelize = new Sequelize(dbConfig);
|
||||
|
||||
const { QueryTypes } = require('sequelize');
|
||||
|
||||
interface Request {
|
||||
profile: string;
|
||||
userId?: string | number;
|
||||
}
|
||||
|
||||
const QueuesByUser = async ({ profile, userId }: Request): Promise<any[]> => {
|
||||
|
||||
let queueByUsersInfo = []
|
||||
|
||||
if (userId) {
|
||||
// CONSULTANDO FILAS PELO ID DO USUARIO
|
||||
queueByUsersInfo = await sequelize.query(`select UserQueues.userId, UserQueues.queueId, Users.name,
|
||||
Queues.name, Queues.color from UserQueues inner join Users inner join Queues on
|
||||
UserQueues.queueId = Queues.id and UserQueues.userId = Users.id and Users.id = '${userId}' and Users.profile = '${profile}' order by userId, queueId;`, { type: QueryTypes.SELECT });
|
||||
|
||||
} else {
|
||||
|
||||
// CONSULTANDO FILAS PELO USUARIO
|
||||
queueByUsersInfo = await sequelize.query(`select UserQueues.userId, UserQueues.queueId, Users.name,
|
||||
Queues.name, Queues.color from UserQueues inner join Users inner join Queues on
|
||||
UserQueues.queueId = Queues.id and UserQueues.userId = Users.id and Users.profile = '${profile}' order by userId, queueId;`, { type: QueryTypes.SELECT });
|
||||
|
||||
}
|
||||
|
||||
return queueByUsersInfo;
|
||||
};
|
||||
|
||||
export default QueuesByUser;
|
||||
|
||||
|
||||
|
||||
|
|
@ -106,6 +106,8 @@ const ShowUserServiceReport = async ({
|
|||
}
|
||||
|
||||
|
||||
// console.log('>>>>>>>>>>>>>> objQuery: ', objQuery)
|
||||
|
||||
|
||||
|
||||
if (!objQuery) {
|
||||
|
|
|
@ -825,6 +825,7 @@ const handleMsgAck = async (msg: WbotMessage, ack: MessageAck) => {
|
|||
action: "update",
|
||||
message: messageToUpdate
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
Sentry.captureException(err);
|
||||
logger.error(`Error handling message ack. Err: ${err}`);
|
||||
|
|
|
@ -0,0 +1,193 @@
|
|||
import React from "react";
|
||||
|
||||
import Paper from "@material-ui/core/Paper";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
|
||||
import Avatar from "@mui/material/Avatar";
|
||||
import Card from "@mui/material/Card";
|
||||
import CardHeader from "@mui/material/CardHeader";
|
||||
import CardContent from "@mui/material/CardContent";
|
||||
import CardActions from "@mui/material/CardActions";
|
||||
|
||||
import { Button } from "@material-ui/core";
|
||||
import Box from "@mui/material/Box";
|
||||
import InputLabel from "@mui/material/InputLabel";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
import FormControl from "@mui/material/FormControl";
|
||||
import Select from "@mui/material/Select";
|
||||
import TextField from "@mui/material/TextField";
|
||||
|
||||
import CancelIcon from "@material-ui/icons/Cancel";
|
||||
import CheckCircleIcon from "@material-ui/icons/CheckCircle";
|
||||
import ErrorIcon from "@material-ui/icons/Error";
|
||||
import RemoveCircleIcon from "@material-ui/icons/RemoveCircle";
|
||||
|
||||
const CardUser = ({ classes, usersOnlineInfo, logout }) => {
|
||||
const [search, setSearch] = React.useState("");
|
||||
|
||||
const [filterStatus, setFilterStatus] = React.useState(null);
|
||||
|
||||
const handleFilterChange = (event) => {
|
||||
setFilterStatus(event.target.value);
|
||||
};
|
||||
const handlesearch = (event) => {
|
||||
setSearch(event.target.value.toLowerCase());
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid item xs={12}>
|
||||
<Paper className={classes.cardPaperFix} sx={12} variant="outlined">
|
||||
<Grid container sx={12} justifyContent="space-between" alignItems="baseline">
|
||||
<Grid item sx={4}>
|
||||
<Typography
|
||||
component="h4"
|
||||
variant="h6"
|
||||
color="primary"
|
||||
style={{ marginBottom: "16px" }}
|
||||
>
|
||||
Lista de Usuários
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item sx={8} width="100%">
|
||||
<Box sx={{ marginBottom: 2, display: "flex", gap: "12px" }}>
|
||||
<TextField
|
||||
id="outlined-basic"
|
||||
label="Usuário"
|
||||
variant="standard"
|
||||
value={search}
|
||||
onChange={handlesearch}
|
||||
/>
|
||||
<FormControl fullWidth variant="standard">
|
||||
<InputLabel id="status">Status</InputLabel>
|
||||
<Select
|
||||
labelId="status"
|
||||
id="status"
|
||||
value={filterStatus}
|
||||
label="Status"
|
||||
onChange={handleFilterChange}
|
||||
>
|
||||
<MenuItem value={null}>Todos</MenuItem>
|
||||
<MenuItem value={"online"}>Online</MenuItem>
|
||||
<MenuItem value={"offline"}>Offline</MenuItem>
|
||||
<MenuItem value={"not"}>Não entrou</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid container spacing={3}>
|
||||
{usersOnlineInfo &&
|
||||
usersOnlineInfo
|
||||
.filter((e) => {
|
||||
if (filterStatus === null) return e;
|
||||
if (filterStatus === "not") return !e.statusOnline;
|
||||
return e.statusOnline && e.statusOnline.status === filterStatus;
|
||||
})
|
||||
.filter((e) => {
|
||||
return e.name.toLowerCase().includes(search);
|
||||
})
|
||||
.sort((a) => {
|
||||
if (a.statusOnline) {
|
||||
if (a.statusOnline.status === "online") {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
})
|
||||
.map((user, index) => (
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
sm={6}
|
||||
md={6}
|
||||
lg={3}
|
||||
key={index}
|
||||
style={{ position: "relative" }}
|
||||
>
|
||||
<Card variant="outlined">
|
||||
<CardHeader
|
||||
avatar={
|
||||
<Avatar
|
||||
style={{
|
||||
backgroundColor: user.statusOnline
|
||||
? user.statusOnline.status === "online"
|
||||
? "green"
|
||||
: user.statusOnline.status === "offline"
|
||||
? "red"
|
||||
: "black"
|
||||
: "grey",
|
||||
}}
|
||||
>
|
||||
{user.statusOnline ? (
|
||||
user.statusOnline.status === "online" ? (
|
||||
<CheckCircleIcon style={{ color: "white" }} />
|
||||
) : user.statusOnline.status === "offline" ? (
|
||||
<CancelIcon style={{ color: "white" }} />
|
||||
) : (
|
||||
<ErrorIcon style={{ color: "yellow" }} />
|
||||
)
|
||||
) : (
|
||||
<RemoveCircleIcon style={{ color: "black" }} />
|
||||
)}
|
||||
</Avatar>
|
||||
}
|
||||
title={
|
||||
<Typography variant="h5" component="div">
|
||||
{user.name}
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
|
||||
<CardContent>
|
||||
<Typography variant="h6" component="h1" color="textPrimary">
|
||||
Em atendimento:
|
||||
<Typography component="p" color="textPrimary" paragraph>
|
||||
{user.sumOpen && user.sumOpen.count ? user.sumOpen.count : 0}
|
||||
</Typography>
|
||||
</Typography>
|
||||
|
||||
<Typography variant="h6" component="h1" color="textPrimary">
|
||||
Finalizado:
|
||||
<Typography component="p" color="textPrimary" paragraph>
|
||||
{user.sumClosed && user.sumClosed.count ? user.sumClosed.count : 0}
|
||||
</Typography>
|
||||
</Typography>
|
||||
|
||||
<Typography variant="h6" component="h1" color="textPrimary">
|
||||
Tempo online:
|
||||
<Typography component="p" color="textPrimary" paragraph>
|
||||
{user.sumOnlineTime && user.sumOnlineTime.sum
|
||||
? user.sumOnlineTime.sum
|
||||
: "Não entrou Hoje"}
|
||||
</Typography>
|
||||
</Typography>
|
||||
</CardContent>
|
||||
<CardActions>
|
||||
{user.statusOnline &&
|
||||
user.statusOnline.status === "online" &&
|
||||
user.statusOnline && (
|
||||
<Button
|
||||
className={classes.logginBtn}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={(e) => {
|
||||
logout(user.id);
|
||||
}}
|
||||
>
|
||||
{"Deslogar"}
|
||||
</Button>
|
||||
)}
|
||||
</CardActions>
|
||||
</Card>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</Paper>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default CardUser;
|
|
@ -0,0 +1,208 @@
|
|||
import React from "react";
|
||||
|
||||
import Select from "@mui/material/Select";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
|
||||
import Table from "@material-ui/core/Table";
|
||||
import TableBody from "@material-ui/core/TableBody";
|
||||
import TableCell from "@material-ui/core/TableCell";
|
||||
import TableContainer from "@material-ui/core/TableContainer";
|
||||
import TableHead from "@material-ui/core/TableHead";
|
||||
import TableRow from "@material-ui/core/TableRow";
|
||||
import Paper from "@material-ui/core/Paper";
|
||||
import Box from "@mui/material/Box";
|
||||
import InputLabel from "@mui/material/InputLabel";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
import FormControl from "@mui/material/FormControl";
|
||||
|
||||
import CancelIcon from "@material-ui/icons/Cancel";
|
||||
import CheckCircleIcon from "@material-ui/icons/CheckCircle";
|
||||
import ErrorIcon from "@material-ui/icons/Error";
|
||||
import RemoveCircleIcon from "@material-ui/icons/RemoveCircle";
|
||||
import PowerSettingsNewIcon from "@material-ui/icons/PowerSettingsNew";
|
||||
|
||||
const TableUser = ({ classes, usersOnlineInfo, logout }) => {
|
||||
const [search, setSearch] = React.useState("");
|
||||
const [filterStatus, setFilterStatus] = React.useState(null);
|
||||
|
||||
const handleFilterChange = (event) => {
|
||||
setFilterStatus(event.target.value);
|
||||
};
|
||||
const handlesearch = (event) => {
|
||||
setSearch(event.target.value.toLowerCase());
|
||||
};
|
||||
|
||||
console.log(usersOnlineInfo);
|
||||
|
||||
return (
|
||||
<Grid item xs={12}>
|
||||
<Paper className={classes.cardPaperFix} sx={12} variant="outlined">
|
||||
<Grid container sx={12} justifyContent="space-between" alignItems="baseline">
|
||||
<Grid item sx={4}>
|
||||
<Typography
|
||||
component="h4"
|
||||
variant="h6"
|
||||
color="primary"
|
||||
style={{ marginBottom: "16px" }}
|
||||
>
|
||||
Lista de Usuários
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item sx={8} width="100%">
|
||||
<Box sx={{ marginBottom: 2, display: "flex", gap: "12px" }}>
|
||||
<TextField
|
||||
id="outlined-basic"
|
||||
label="Usuário"
|
||||
variant="standard"
|
||||
value={search}
|
||||
onChange={handlesearch}
|
||||
/>
|
||||
<FormControl fullWidth variant="standard">
|
||||
<InputLabel id="status">Status</InputLabel>
|
||||
<Select
|
||||
labelId="status"
|
||||
id="status"
|
||||
value={filterStatus}
|
||||
label="Status"
|
||||
onChange={handleFilterChange}
|
||||
>
|
||||
<MenuItem value={null}>Todos</MenuItem>
|
||||
<MenuItem value={"online"}>Online</MenuItem>
|
||||
<MenuItem value={"offline"}>Offline</MenuItem>
|
||||
<MenuItem value={"not"}>Não entrou</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid container spacing={3} style={{ marginTop: "16px", marginBottom: "16px" }}>
|
||||
<TableContainer component={Paper}>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow className={classes.tableRowHead}>
|
||||
<TableCell>Nome</TableCell>
|
||||
<TableCell>Em Atendimento/Finalizado(s)</TableCell>
|
||||
<TableCell>Por Fila abertos</TableCell>
|
||||
<TableCell>Por Fila Fechados</TableCell>
|
||||
<TableCell>Tempo Online</TableCell>
|
||||
<TableCell>Ações</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
|
||||
<TableBody>
|
||||
{usersOnlineInfo &&
|
||||
usersOnlineInfo
|
||||
.filter((e) => {
|
||||
if (filterStatus === null) return e;
|
||||
if (filterStatus === "not") return !e.statusOnline;
|
||||
return e.statusOnline && e.statusOnline.status === filterStatus;
|
||||
})
|
||||
.filter((e) => {
|
||||
return e.name.toLowerCase().includes(search);
|
||||
})
|
||||
.sort((a) => {
|
||||
if (a.statusOnline) {
|
||||
if (a.statusOnline.status === "online") {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
})
|
||||
.map((user, index) => (
|
||||
<TableRow key={index} className={classes.tableRowBody}>
|
||||
<TableCell>
|
||||
<Typography
|
||||
style={{ display: "flex", verticalAlign: "center", gap: "6px" }}
|
||||
>
|
||||
{user.statusOnline ? (
|
||||
user.statusOnline.status === "online" ? (
|
||||
<CheckCircleIcon style={{ color: "green" }} />
|
||||
) : user.statusOnline.status === "offline" ? (
|
||||
<CancelIcon style={{ color: "red" }} />
|
||||
) : (
|
||||
<ErrorIcon style={{ color: "gold" }} />
|
||||
)
|
||||
) : (
|
||||
<RemoveCircleIcon style={{ color: "black" }} />
|
||||
)}
|
||||
{user.name}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
|
||||
<TableCell>
|
||||
<div style={{ display: "flex", alignItems: "center", gap: "12px" }}>
|
||||
<Typography className={classes.tableCounterOpen}>
|
||||
{user.sumOpen ? user.sumOpen.count : "0"}
|
||||
</Typography>
|
||||
<Typography className={classes.tableCounterClosed}>
|
||||
{user.sumClosed ? user.sumClosed.count : "0"}
|
||||
</Typography>
|
||||
</div>
|
||||
</TableCell>
|
||||
|
||||
<TableCell>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexWrap: "wrap",
|
||||
alignItems: "center",
|
||||
gap: "12px",
|
||||
}}
|
||||
>
|
||||
<Typography title="Cobrança">0</Typography>
|
||||
<Typography>0</Typography>
|
||||
<Typography>0</Typography>
|
||||
<Typography>0</Typography>
|
||||
<Typography>0</Typography>
|
||||
</div>
|
||||
</TableCell>
|
||||
|
||||
<TableCell>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexWrap: "wrap",
|
||||
alignItems: "center",
|
||||
gap: "12px",
|
||||
}}
|
||||
>
|
||||
<Typography title="Cobrança">0</Typography>
|
||||
<Typography>0</Typography>
|
||||
<Typography>0</Typography>
|
||||
<Typography>0</Typography>
|
||||
<Typography>0</Typography>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{user.sumOnlineTime ? user.sumOnlineTime.sum : "Não entrou"}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{user.statusOnline && user.statusOnline.status === "online" ? (
|
||||
<PowerSettingsNewIcon
|
||||
style={{ color: "red", cursor: "pointer" }}
|
||||
onClick={(e) => {
|
||||
logout(user.id);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<PowerSettingsNewIcon
|
||||
style={{ color: "grey", cursor: "not-allowed" }}
|
||||
/>
|
||||
)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Grid>
|
||||
</Paper>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default TableUser;
|
|
@ -362,15 +362,17 @@ const MessagesList = ({ ticketId, isGroup }) => {
|
|||
socket.on("connect", () => socket.emit("joinChatBox", ticketId));
|
||||
|
||||
socket.on("appMessage", (data) => {
|
||||
|
||||
if (data.action === "create") {
|
||||
dispatch({ type: "ADD_MESSAGE", payload: data.message });
|
||||
|
||||
// console.log('* NOVA MENSAGEM CAP: ', data.message)
|
||||
|
||||
scrollToBottom();
|
||||
}
|
||||
|
||||
if (data.action === "update") {
|
||||
|
||||
console.log('2 THIS IS THE DATA: ', data)
|
||||
|
||||
dispatch({ type: "UPDATE_MESSAGE", payload: data.message });
|
||||
}
|
||||
});
|
||||
|
|
|
@ -4,36 +4,76 @@ import MaterialTable from 'material-table';
|
|||
import Modal from '../Modal'
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
import chat from '@material-ui/icons/Chat';
|
||||
|
||||
// import Button from "@material-ui/core/Button";
|
||||
|
||||
import React from 'react';
|
||||
|
||||
const MTable = (props) => {
|
||||
|
||||
const [selectedRow, setSelectedRow] = useState(null);
|
||||
const tableRef = React.useRef();
|
||||
|
||||
const openInNewTab = url => {
|
||||
window.open(url, '_blank', 'noopener,noreferrer');
|
||||
};
|
||||
|
||||
const [selectedRow, setSelectedRow] = useState(null);
|
||||
|
||||
//const dataLoad = props.data.map((dt) => { return { ...dt }});
|
||||
const dataLoad = props.data.map(({ user, ...others }) => ({ ...others, 'user': user ? user : { name: 'Aguardando atendente', email: '' } }));
|
||||
|
||||
const columnsLoad = props.columns.map((column) => { return { ...column } });
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
console.log(`You have clicked the button ${selectedRow} times`)
|
||||
|
||||
// console.log('TABLE REF: ', tableRef)
|
||||
|
||||
}, [selectedRow]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
if (!tableRef.current) return
|
||||
|
||||
const element = tableRef.current.tableContainerDiv.current;
|
||||
|
||||
element.addEventListener('scroll', props.handleScroll);
|
||||
|
||||
return () => {
|
||||
element.removeEventListener('scroll', props.handleScroll);
|
||||
};
|
||||
|
||||
}, [props]);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return (
|
||||
|
||||
<>
|
||||
{/* <Button onClick={handleTest}>Toggle</Button> */}
|
||||
|
||||
{/* <CircularProgress /> */}
|
||||
|
||||
<MaterialTable
|
||||
title={props.table_title}
|
||||
columns={columnsLoad}
|
||||
data={dataLoad}
|
||||
|
||||
maxWidth={true}
|
||||
|
||||
tableRef={tableRef}
|
||||
|
||||
localization={{ header: { actions: props.hasChild ? 'Ticket' : null },}}
|
||||
|
||||
onRowClick={(evt, selectedRow) => {
|
||||
|
||||
if(props.removeClickRow){
|
||||
if (props.removeClickRow) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -56,23 +96,52 @@ const MTable = (props) => {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
actions={[
|
||||
(rowData) => {
|
||||
|
||||
if(props.hasChild){
|
||||
return {
|
||||
icon: chat,
|
||||
tooltip: `Ticket id ${rowData.id}`,
|
||||
disable: false,
|
||||
onClick: (event, rowData) => {
|
||||
|
||||
openInNewTab(`/tickets/${rowData.id}`)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]}
|
||||
|
||||
options={{
|
||||
search: true,
|
||||
selection: false,
|
||||
paging: false,
|
||||
padding: 'dense',
|
||||
|
||||
exportButton: props.hasChild ? true : null,
|
||||
exportAllData: true,
|
||||
|
||||
sorting: true ? props.hasChild : false,
|
||||
//loadingType: 'linear',
|
||||
// loadingType: 'circular',
|
||||
searchFieldStyle: {
|
||||
width: 300,
|
||||
},
|
||||
|
||||
pageSize: 20,
|
||||
|
||||
headerStyle: {
|
||||
position: "sticky",
|
||||
top: "0"
|
||||
},
|
||||
|
||||
maxBodyHeight: "400px",
|
||||
// minBodyHeight: "85vh", //FIXME to calculate dynamic height, needed for correct scroll position identification
|
||||
// maxBodyHeight: "85vh",
|
||||
|
||||
|
||||
|
||||
rowStyle: rowData => ({
|
||||
fontSize: 12,
|
||||
|
@ -80,6 +149,9 @@ const MTable = (props) => {
|
|||
})
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
|
||||
|
||||
);
|
||||
|
||||
};
|
||||
|
|
|
@ -12,6 +12,7 @@ import useTickets from "../../hooks/useTickets";
|
|||
import { i18n } from "../../translate/i18n";
|
||||
import { AuthContext } from "../../context/Auth/AuthContext";
|
||||
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
ticketsListWrapper: {
|
||||
position: "relative",
|
||||
|
@ -134,8 +135,8 @@ const reducer = (state, action) => {
|
|||
|
||||
// console.log('&&&&&&& UPDATE_TICKET_UNREAD_MESSAGES ticket: ',ticket, ' |\n MESSAGE: ', message)
|
||||
|
||||
if(!message.fromMe){
|
||||
ticket.unreadMessages +=1
|
||||
if (!message.fromMe) {
|
||||
ticket.unreadMessages += 1
|
||||
}
|
||||
|
||||
state[ticketIndex] = ticket;
|
||||
|
@ -195,6 +196,9 @@ const TicketsList = (props) => {
|
|||
|
||||
useEffect(() => {
|
||||
if (!status && !searchParam) return;
|
||||
|
||||
// console.log('lllllllllllllllllllllllllllllllll')
|
||||
|
||||
dispatch({
|
||||
type: "LOAD_TICKETS",
|
||||
payload: tickets,
|
||||
|
@ -221,6 +225,7 @@ const TicketsList = (props) => {
|
|||
});
|
||||
|
||||
socket.on("ticket", data => {
|
||||
|
||||
if (data.action === "updateUnread") {
|
||||
dispatch({
|
||||
type: "RESET_UNREAD",
|
||||
|
@ -286,6 +291,7 @@ const TicketsList = (props) => {
|
|||
};
|
||||
|
||||
const handleScroll = e => {
|
||||
|
||||
if (!hasMore || loading) return;
|
||||
|
||||
const { scrollTop, scrollHeight, clientHeight } = e.currentTarget;
|
||||
|
|
|
@ -125,7 +125,6 @@ const TicketsManager = () => {
|
|||
|
||||
const handleSearch = (e) => {
|
||||
const searchedTerm = e.target.value.toLowerCase().trim();
|
||||
console.log(searchedTerm)
|
||||
|
||||
clearTimeout(searchTimeout);
|
||||
|
||||
|
|
|
@ -39,6 +39,19 @@ const reducer = (state, action) => {
|
|||
}
|
||||
|
||||
|
||||
// if (action.type === "UPDATE_DISK_SPACE_MONIT") {
|
||||
// const whatsApp = action.payload;
|
||||
// const whatsAppIndex = state.findIndex(s => s.id === whatsApp.id);
|
||||
|
||||
// if (whatsAppIndex !== -1) {
|
||||
// state[whatsAppIndex].sessionSize = whatsApp.sessionSize;
|
||||
// return [...state];
|
||||
// } else {
|
||||
// return [whatsApp, ...state];
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
if (action.type === "UPDATE_WHATSAPPS_SESSION_MONIT") {
|
||||
const whatsApp = action.payload;
|
||||
const whatsAppIndex = state.findIndex(s => s.id === whatsApp.id);
|
||||
|
@ -108,10 +121,6 @@ const useWhatsApps = () => {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
//test del
|
||||
|
||||
socket.on("whatsappSessionMonit", data => {
|
||||
if (data.action === "update") {
|
||||
|
||||
|
@ -121,7 +130,7 @@ const useWhatsApps = () => {
|
|||
}
|
||||
});
|
||||
|
||||
//
|
||||
|
||||
|
||||
return () => {
|
||||
socket.disconnect();
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import React, { useState, useCallback, useContext } from "react";
|
||||
import React, { useState, useCallback, useEffect, useContext } from "react";
|
||||
import { toast } from "react-toastify";
|
||||
import { format, parseISO } from "date-fns";
|
||||
|
||||
import openSocket from "socket.io-client";
|
||||
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import { green } from "@material-ui/core/colors";
|
||||
import {
|
||||
|
@ -111,6 +113,8 @@ const Connections = () => {
|
|||
const [selectedWhatsApp, setSelectedWhatsApp] = useState(null);
|
||||
const [confirmModalOpen, setConfirmModalOpen] = useState(false);
|
||||
|
||||
const [diskSpaceInfo, setDiskSpaceInfo] = useState({});
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -324,6 +328,23 @@ const Connections = () => {
|
|||
);
|
||||
};
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const socket = openSocket(process.env.REACT_APP_BACKEND_URL);
|
||||
|
||||
socket.on("diskSpaceMonit", data => {
|
||||
if (data.action === "update") {
|
||||
|
||||
setDiskSpaceInfo(data.diskSpace)
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
socket.disconnect();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
||||
<Can
|
||||
|
@ -355,7 +376,10 @@ const Connections = () => {
|
|||
/>
|
||||
|
||||
<MainHeader>
|
||||
|
||||
|
||||
<Title>{i18n.t("connections.title")}</Title>
|
||||
|
||||
<MainHeaderButtonsWrapper>
|
||||
<Can
|
||||
role={user.profile}
|
||||
|
@ -370,10 +394,51 @@ const Connections = () => {
|
|||
)}
|
||||
/>
|
||||
</MainHeaderButtonsWrapper>
|
||||
|
||||
|
||||
</MainHeader>
|
||||
|
||||
|
||||
<Paper className={classes.mainPaper} variant="outlined">
|
||||
<>
|
||||
|
||||
<Can
|
||||
role={user.profile}
|
||||
perform="space-disk-info:show"
|
||||
yes={() => (
|
||||
<>
|
||||
<Table size="small">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell align="center">
|
||||
Size
|
||||
</TableCell>
|
||||
<TableCell align="center">
|
||||
Used
|
||||
</TableCell>
|
||||
<TableCell align="center">
|
||||
Available
|
||||
</TableCell>
|
||||
<TableCell align="center">
|
||||
Use%
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell align="center">{diskSpaceInfo.size}</TableCell>
|
||||
<TableCell align="center">{diskSpaceInfo.used}</TableCell>
|
||||
<TableCell align="center">{diskSpaceInfo.available}</TableCell>
|
||||
<TableCell align="center">{diskSpaceInfo.use}</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
<br />
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Table size="small">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
|
@ -557,6 +622,8 @@ const Connections = () => {
|
|||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
||||
</>
|
||||
</Paper>
|
||||
</MainContainer>
|
||||
)}
|
||||
|
|
|
@ -36,17 +36,23 @@ import { AuthContext } from "../../context/Auth/AuthContext";
|
|||
import { Can } from "../../components/Can";
|
||||
|
||||
const reducer = (state, action) => {
|
||||
|
||||
|
||||
if (action.type === "LOAD_CONTACTS") {
|
||||
|
||||
const contacts = action.payload;
|
||||
const newContacts = [];
|
||||
|
||||
contacts.forEach((contact) => {
|
||||
|
||||
const contactIndex = state.findIndex((c) => c.id === contact.id);
|
||||
|
||||
if (contactIndex !== -1) {
|
||||
state[contactIndex] = contact;
|
||||
} else {
|
||||
newContacts.push(contact);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return [...state, ...newContacts];
|
||||
|
@ -210,6 +216,9 @@ const Contacts = () => {
|
|||
const handleScroll = (e) => {
|
||||
if (!hasMore || loading) return;
|
||||
const { scrollTop, scrollHeight, clientHeight } = e.currentTarget;
|
||||
|
||||
// console.log('scrollTop: ', scrollTop, ' | scrollHeight: ', scrollHeight, ' | clientHeight: ', clientHeight)
|
||||
|
||||
if (scrollHeight - (scrollTop + 100) < clientHeight) {
|
||||
loadMore();
|
||||
}
|
||||
|
|
|
@ -16,11 +16,11 @@ import { i18n } from "../../translate/i18n";
|
|||
import Title from "./Title";
|
||||
import useTickets from "../../hooks/useTickets";
|
||||
|
||||
const Chart = () => {
|
||||
const Chart = (props) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const date = useRef(new Date().toISOString());
|
||||
const { tickets } = useTickets({ date: date.current });
|
||||
let { tickets } = useTickets({ date: date.current, unlimited: "true" });
|
||||
|
||||
const [chartData, setChartData] = useState([
|
||||
{ time: "08:00", amount: 0 },
|
||||
|
@ -42,10 +42,7 @@ const Chart = () => {
|
|||
let aux = [...prevState];
|
||||
|
||||
aux.forEach(a => {
|
||||
tickets.forEach(ticket => {
|
||||
format(startOfHour(parseISO(ticket.createdAt)), "HH:mm") === a.time &&
|
||||
a.amount++;
|
||||
});
|
||||
tickets.forEach(ticket => { format(startOfHour(parseISO(ticket.createdAt)), "HH:mm") === a.time && a.amount++; });
|
||||
});
|
||||
|
||||
return aux;
|
||||
|
@ -54,8 +51,7 @@ const Chart = () => {
|
|||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Title>{`${i18n.t("dashboard.charts.perDay.title")}${
|
||||
tickets.length
|
||||
<Title>{`${i18n.t("dashboard.charts.perDay.title")}${tickets.length
|
||||
}`}</Title>
|
||||
<ResponsiveContainer>
|
||||
<BarChart
|
||||
|
|
|
@ -5,25 +5,10 @@ import Container from "@material-ui/core/Container";
|
|||
import Grid from "@material-ui/core/Grid";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import Card from "@mui/material/Card";
|
||||
import CardHeader from "@mui/material/CardHeader";
|
||||
import CardContent from "@mui/material/CardContent";
|
||||
import CardActions from "@mui/material/CardActions";
|
||||
import Avatar from "@mui/material/Avatar";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import Zoom from "@mui/material/Zoom";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import Box from "@mui/material/Box";
|
||||
import InputLabel from "@mui/material/InputLabel";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
import FormControl from "@mui/material/FormControl";
|
||||
import Select from "@mui/material/Select";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Info from "@material-ui/icons/Info";
|
||||
import CancelIcon from "@material-ui/icons/Cancel";
|
||||
import CheckCircleIcon from "@material-ui/icons/CheckCircle";
|
||||
import ErrorIcon from "@material-ui/icons/Error";
|
||||
import RemoveCircleIcon from "@material-ui/icons/RemoveCircle";
|
||||
|
||||
import useTickets from "../../hooks/useTickets";
|
||||
|
||||
|
@ -38,9 +23,8 @@ import openSocket from "socket.io-client";
|
|||
import api from "../../services/api";
|
||||
|
||||
import { Can } from "../../components/Can";
|
||||
|
||||
import { Button } from "@material-ui/core";
|
||||
import { id } from "date-fns/locale";
|
||||
import CardUser from "../../components/DashboardUser/CardUser";
|
||||
import TableUser from "../../components/DashboardUser/TableUser";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
container: {
|
||||
|
@ -78,10 +62,10 @@ const useStyles = makeStyles((theme) => ({
|
|||
},
|
||||
cardPaperFix: {
|
||||
textTransform: "capitalize",
|
||||
padding: theme.spacing(2),
|
||||
paddingBottom: theme.spacing(4),
|
||||
height: "500px",
|
||||
overflowY: "scroll",
|
||||
paddingLeft: theme.spacing(4),
|
||||
paddingRight: theme.spacing(4),
|
||||
height: window.innerWidth <= 992 ? "500px" : "auto",
|
||||
overflowY: "hidden",
|
||||
},
|
||||
cardStyleFix: {
|
||||
display: "flex",
|
||||
|
@ -96,6 +80,29 @@ const useStyles = makeStyles((theme) => ({
|
|||
right: "21px",
|
||||
fontSize: "12px",
|
||||
},
|
||||
tableRowHead: {
|
||||
backgroundColor: "lightgrey",
|
||||
},
|
||||
tableRowBody: {
|
||||
textAlign: "center",
|
||||
" &:nth-child(even)": {
|
||||
backgroundColor: "#f7f7f7",
|
||||
},
|
||||
},
|
||||
tableCounterOpen: {
|
||||
color: "white",
|
||||
backgroundColor: "green",
|
||||
width: "25px",
|
||||
textAlign: "center",
|
||||
borderRadius: "5px",
|
||||
},
|
||||
tableCounterClosed: {
|
||||
color: "white",
|
||||
backgroundColor: "red",
|
||||
width: "25px",
|
||||
textAlign: "center",
|
||||
borderRadius: "5px",
|
||||
},
|
||||
}));
|
||||
|
||||
const reducer = (state, action) => {
|
||||
|
@ -168,19 +175,30 @@ const reducer = (state, action) => {
|
|||
|
||||
if (onlineUser.sumOpen) {
|
||||
if ("sumOpen" in state[index]) {
|
||||
// console.log(' >>>>>>>>>>>>>>>>>> sumOpen 1 | state[index].sumOpen["count"]: ', state[index].sumOpen['count'], ' | onlineUser.sumOpen.count: ', onlineUser.sumOpen.count)
|
||||
state[index].sumOpen["count"] = onlineUser.sumOpen.count;
|
||||
} else if (!("sumOpen" in state[index])) {
|
||||
// console.log(' >>>>>>>>>>>>>>>>>> sumOpen 1')
|
||||
state[index].sumOpen = onlineUser.sumOpen;
|
||||
}
|
||||
}
|
||||
|
||||
if (onlineUser.sumClosed) {
|
||||
if ("sumClosed" in state[index]) {
|
||||
// console.log(' >>>>>>>>>>>>>>>>>> sumClosed 1 | state[index].sumClosed["count"]: ', state[index].sumClosed['count'], ' | onlineUser.sumClosed.count: ', onlineUser.sumClosed.count)
|
||||
state[index].sumClosed["count"] = onlineUser.sumClosed.count;
|
||||
} else if (!("sumClosed" in state[index])) {
|
||||
// console.log(' >>>>>>>>>>>>>>>>>> sumOpen 1')
|
||||
state[index].sumClosed = onlineUser.sumClosed;
|
||||
}
|
||||
}
|
||||
|
||||
if (onlineUser.openClosedInQueue) {
|
||||
state[index].openClosedInQueue = onlineUser.openClosedInQueue;
|
||||
}
|
||||
if (onlineUser.openClosedOutQueue) {
|
||||
state[index].openClosedOutQueue = onlineUser.openClosedOutQueue;
|
||||
}
|
||||
}
|
||||
return [...state];
|
||||
}
|
||||
|
@ -193,25 +211,12 @@ const reducer = (state, action) => {
|
|||
const Dashboard = () => {
|
||||
const classes = useStyles();
|
||||
const [usersOnlineInfo, dispatch] = useReducer(reducer, []);
|
||||
const [search, setSearch] = useState("");
|
||||
const [filterStatus, setFilterStatus] = useState(null);
|
||||
const [ticketStatusChange, setStatus] = useState();
|
||||
const [open, setOpen] = useState(0);
|
||||
const [closed, setClosed] = useState(0);
|
||||
const [pending, setPending] = useState(0);
|
||||
|
||||
const { user } = useContext(AuthContext);
|
||||
var userQueueIds = [];
|
||||
|
||||
if (user.queues && user.queues.length > 0) {
|
||||
userQueueIds = user.queues.map((q) => q.id);
|
||||
}
|
||||
|
||||
const GetTickets = (status, showAll, withUnreadMessages, unlimited) => {
|
||||
const { tickets } = useTickets({
|
||||
status: status,
|
||||
showAll: showAll,
|
||||
withUnreadMessages: withUnreadMessages,
|
||||
queueIds: JSON.stringify(userQueueIds),
|
||||
unlimited: unlimited,
|
||||
});
|
||||
return tickets.length;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
dispatch({ type: "RESET" });
|
||||
|
@ -243,6 +248,8 @@ const Dashboard = () => {
|
|||
dispatch({ type: "RESET" });
|
||||
dispatch({ type: "LOAD_QUERY", payload: dataQuery.data });
|
||||
|
||||
console.log("xxx REPORT 2 dataQuery : ", dataQuery.data);
|
||||
|
||||
//console.log()
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
|
@ -257,8 +264,18 @@ const Dashboard = () => {
|
|||
useEffect(() => {
|
||||
const socket = openSocket(process.env.REACT_APP_BACKEND_URL);
|
||||
|
||||
socket.on("ticketStatus", (data) => {
|
||||
// console.log('data: ',data)
|
||||
|
||||
if (data.action === "update") {
|
||||
setStatus(data.ticketStatus.status);
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("onlineStatus", (data) => {
|
||||
if (data.action === "logout" || data.action === "update") {
|
||||
// console.log('>>>>>>> data.userOnlineTime: ', data.userOnlineTime)
|
||||
|
||||
dispatch({ type: "UPDATE_STATUS_ONLINE", payload: data.userOnlineTime });
|
||||
} else if (data.action === "delete") {
|
||||
dispatch({ type: "DELETE_USER_STATUS", payload: data.userOnlineTime });
|
||||
|
@ -277,13 +294,36 @@ const Dashboard = () => {
|
|||
};
|
||||
}, []);
|
||||
|
||||
const handleFilterChange = (event) => {
|
||||
setFilterStatus(event.target.value);
|
||||
};
|
||||
const handlesearch = (event) => {
|
||||
setSearch(event.target.value.toLowerCase());
|
||||
useEffect(() => {
|
||||
const delayDebounceFn = setTimeout(() => {
|
||||
const fetchQueries = async () => {
|
||||
try {
|
||||
let date = new Date().toLocaleDateString("pt-BR").split("/");
|
||||
let dateToday = `${date[2]}-${date[1]}-${date[0]}`;
|
||||
|
||||
const _open = await api.get("/tickets/count", {
|
||||
params: { status: "open", date: dateToday },
|
||||
});
|
||||
const _closed = await api.get("/tickets/count", {
|
||||
params: { status: "closed", date: dateToday },
|
||||
});
|
||||
const _pending = await api.get("/tickets/count", {
|
||||
params: { status: "pending", date: dateToday },
|
||||
});
|
||||
|
||||
setOpen(_open.data.count);
|
||||
setClosed(_closed.data.count);
|
||||
setPending(_pending.data.count);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
};
|
||||
|
||||
fetchQueries();
|
||||
}, 500);
|
||||
return () => clearTimeout(delayDebounceFn);
|
||||
}, [ticketStatusChange]);
|
||||
|
||||
return (
|
||||
<Can
|
||||
role={user.profile}
|
||||
|
@ -323,7 +363,7 @@ const Dashboard = () => {
|
|||
</Typography>
|
||||
<Grid item>
|
||||
<Typography component="h1" variant="h4">
|
||||
{GetTickets("open", "true", "false", "true")}
|
||||
{open}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Paper>
|
||||
|
@ -339,7 +379,7 @@ const Dashboard = () => {
|
|||
</Typography>
|
||||
<Grid item>
|
||||
<Typography component="h1" variant="h4">
|
||||
{GetTickets("pending", "true", "false", "true")}
|
||||
{pending}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Paper>
|
||||
|
@ -355,7 +395,7 @@ const Dashboard = () => {
|
|||
</Typography>
|
||||
<Grid item>
|
||||
<Typography component="h1" variant="h4">
|
||||
{GetTickets("closed", "true", "false", "true")}
|
||||
{closed}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Paper>
|
||||
|
@ -446,158 +486,19 @@ const Dashboard = () => {
|
|||
</Grid>
|
||||
</Paper>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Paper className={classes.cardPaperFix} sx={12} variant="outlined">
|
||||
<Grid container sx={12} justifyContent="space-between">
|
||||
<Grid item sx={4}>
|
||||
<Typography
|
||||
component="h4"
|
||||
variant="h6"
|
||||
color="primary"
|
||||
style={{ marginBottom: "16px" }}
|
||||
>
|
||||
Lista de Usuários
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item sx={8} width="100%">
|
||||
<Box sx={{ marginBottom: 2, display: "flex", gap: "12px" }}>
|
||||
<TextField
|
||||
id="outlined-basic"
|
||||
label="Usuário"
|
||||
variant="standard"
|
||||
value={search}
|
||||
onChange={handlesearch}
|
||||
{window.innerWidth <= 992 ? (
|
||||
<CardUser
|
||||
classes={classes}
|
||||
usersOnlineInfo={usersOnlineInfo}
|
||||
logout={handleLogouOnlineUser}
|
||||
/>
|
||||
<FormControl fullWidth variant="standard">
|
||||
<InputLabel id="status">Status</InputLabel>
|
||||
<Select
|
||||
labelId="status"
|
||||
id="status"
|
||||
value={filterStatus}
|
||||
label="Status"
|
||||
onChange={handleFilterChange}
|
||||
>
|
||||
<MenuItem value={null}>Todos</MenuItem>
|
||||
<MenuItem value={"online"}>Online</MenuItem>
|
||||
<MenuItem value={"offline"}>Offline</MenuItem>
|
||||
<MenuItem value={"not"}>Não entrou</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid container spacing={3}>
|
||||
{usersOnlineInfo &&
|
||||
usersOnlineInfo
|
||||
.filter((e) => {
|
||||
if (filterStatus === null) return e;
|
||||
if (filterStatus === "not") return !e.statusOnline;
|
||||
return e.statusOnline && e.statusOnline.status === filterStatus;
|
||||
})
|
||||
.filter((e) => {
|
||||
return e.name.toLowerCase().includes(search);
|
||||
}).sort((a) => {
|
||||
if (a.statusOnline) {
|
||||
if (a.statusOnline.status === "online") {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
})
|
||||
.map((user, index) => (
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
sm={6}
|
||||
md={6}
|
||||
lg={3}
|
||||
key={index}
|
||||
style={{ position: "relative" }}
|
||||
>
|
||||
<Card variant="outlined">
|
||||
<CardHeader
|
||||
avatar={
|
||||
<Avatar
|
||||
style={{
|
||||
backgroundColor: user.statusOnline
|
||||
? user.statusOnline.status === "online"
|
||||
? "green"
|
||||
: user.statusOnline.status === "offline"
|
||||
? "red"
|
||||
: "black"
|
||||
: "grey",
|
||||
}}
|
||||
>
|
||||
{user.statusOnline ? (
|
||||
user.statusOnline.status === "online" ? (
|
||||
<CheckCircleIcon style={{ color: "white" }} />
|
||||
) : user.statusOnline.status === "offline" ? (
|
||||
<CancelIcon style={{ color: "white" }} />
|
||||
) : (
|
||||
<ErrorIcon style={{ color: "yellow" }} />
|
||||
)
|
||||
) : (
|
||||
<RemoveCircleIcon style={{ color: "black" }} />
|
||||
)}
|
||||
</Avatar>
|
||||
}
|
||||
title={
|
||||
<Typography variant="h5" component="div">
|
||||
{user.name}
|
||||
</Typography>
|
||||
}
|
||||
<TableUser
|
||||
classes={classes}
|
||||
usersOnlineInfo={usersOnlineInfo}
|
||||
logout={handleLogouOnlineUser}
|
||||
/>
|
||||
|
||||
<CardContent>
|
||||
<Typography variant="h6" component="h1" color="textPrimary">
|
||||
Em atendimento:
|
||||
<Typography component="p" color="textPrimary" paragraph>
|
||||
{user.sumOpen && user.sumOpen.count ? user.sumOpen.count : 0}
|
||||
</Typography>
|
||||
</Typography>
|
||||
|
||||
<Typography variant="h6" component="h1" color="textPrimary">
|
||||
Finalizado:
|
||||
<Typography component="p" color="textPrimary" paragraph>
|
||||
{user.sumClosed && user.sumClosed.count
|
||||
? user.sumClosed.count
|
||||
: 0}
|
||||
</Typography>
|
||||
</Typography>
|
||||
|
||||
<Typography variant="h6" component="h1" color="textPrimary">
|
||||
Tempo online:
|
||||
<Typography component="p" color="textPrimary" paragraph>
|
||||
{user.sumOnlineTime && user.sumOnlineTime.sum
|
||||
? user.sumOnlineTime.sum
|
||||
: "Não entrou Hoje"}
|
||||
</Typography>
|
||||
</Typography>
|
||||
</CardContent>
|
||||
<CardActions>
|
||||
{user.statusOnline &&
|
||||
user.statusOnline.status === "online" &&
|
||||
user.statusOnline && (
|
||||
<Button
|
||||
className={classes.logginBtn}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={(e) => {
|
||||
handleLogouOnlineUser(user.id);
|
||||
}}
|
||||
>
|
||||
{"Deslogar"}
|
||||
</Button>
|
||||
)}
|
||||
</CardActions>
|
||||
</Card>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</Paper>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Paper>
|
||||
</Grid>
|
||||
|
|
|
@ -18,8 +18,11 @@ import MaterialTable from 'material-table';
|
|||
|
||||
import LogoutIcon from '@material-ui/icons/CancelOutlined';
|
||||
|
||||
|
||||
|
||||
import { CSVLink } from "react-csv";
|
||||
|
||||
// import CircularProgress from '@mui/material/CircularProgress';
|
||||
|
||||
import openSocket from "socket.io-client";
|
||||
|
||||
|
@ -117,7 +120,6 @@ const reducerQ = (state, action) => {
|
|||
|
||||
if (action.type === 'LOAD_QUERY') {
|
||||
|
||||
|
||||
const queries = action.payload
|
||||
const newQueries = []
|
||||
|
||||
|
@ -301,19 +303,26 @@ let columnsData = [
|
|||
|
||||
{ title: 'Criado', field: 'createdAt' },
|
||||
//{title: 'Atualizado', field: 'updatedAt'},
|
||||
{title: 'Status de encerramento', field: 'statusChatEnd'}];
|
||||
{ title: 'Status de encerramento', field: 'statusChatEnd' }];
|
||||
|
||||
|
||||
const Report = () => {
|
||||
|
||||
const csvLink = useRef()
|
||||
|
||||
|
||||
const { user: userA } = useContext(AuthContext);
|
||||
|
||||
//--------
|
||||
const [searchParam] = useState("");
|
||||
//const [loading, setLoading] = useState(false);
|
||||
//const [hasMore, setHasMore] = useState(false);
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
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 [columns, setColums] = useState([])
|
||||
|
@ -336,7 +345,7 @@ const Report = () => {
|
|||
useEffect(() => {
|
||||
dispatch({ type: "RESET" });
|
||||
dispatchQ({ type: "RESET" })
|
||||
|
||||
setTicketsPageNumber(1)
|
||||
setPageNumber(1);
|
||||
}, [searchParam, profile]);
|
||||
|
||||
|
@ -380,20 +389,24 @@ const Report = () => {
|
|||
|
||||
const delayDebounceFn = setTimeout(() => {
|
||||
|
||||
setLoading(true);
|
||||
const fetchQueries = async () => {
|
||||
try {
|
||||
|
||||
if (reportOption === '1') {
|
||||
|
||||
const dataQuery = await api.get("/reports/", { params: { userId, startDate, endDate }, });
|
||||
dispatchQ({ type: "RESET" })
|
||||
dispatchQ({ type: "LOAD_QUERY", payload: dataQuery.data });
|
||||
const { data } = await api.get("/reports/", { params: { userId, startDate, endDate, pageNumber: pageNumberTickets }, });
|
||||
|
||||
//setLoading(false);
|
||||
// console.log('dataQuery: ', data)
|
||||
// console.log('pageNumberTickets: ', pageNumberTickets)
|
||||
|
||||
// console.log('dataQuery: ', dataQuery.data)
|
||||
// dispatchQ({ type: "RESET" })
|
||||
dispatchQ({ type: "LOAD_QUERY", payload: data.tickets });
|
||||
|
||||
setHasMore(data.hasMore);
|
||||
setTotalCountTickets(data.count)
|
||||
setLoading(false);
|
||||
|
||||
// console.log()
|
||||
|
||||
}
|
||||
else if (reportOption === '2') {
|
||||
|
@ -404,7 +417,7 @@ const Report = () => {
|
|||
|
||||
//setLoading(false);
|
||||
|
||||
// console.log('REPORT 2 dataQuery : ', dataQuery.data)
|
||||
console.log('REPORT 2 dataQuery : ', dataQuery.data)
|
||||
|
||||
//console.log()
|
||||
|
||||
|
@ -420,7 +433,7 @@ const Report = () => {
|
|||
}, 500);
|
||||
return () => clearTimeout(delayDebounceFn);
|
||||
|
||||
}, [userId, startDate, endDate, reportOption]);
|
||||
}, [userId, startDate, endDate, reportOption, pageNumberTickets, totalCountTickets]);
|
||||
|
||||
|
||||
// Get from child 1
|
||||
|
@ -464,27 +477,15 @@ const Report = () => {
|
|||
}, [reportOption])
|
||||
|
||||
|
||||
// useEffect(() => {
|
||||
|
||||
// console.log('>>>>>>>>>>>>>>>>>> New query: ', query)
|
||||
|
||||
// }, [query])
|
||||
|
||||
|
||||
|
||||
// test del
|
||||
|
||||
const handleCSVMessages = () => {
|
||||
|
||||
// setLoading(true);
|
||||
|
||||
const fetchQueries = async () => {
|
||||
|
||||
try {
|
||||
|
||||
const dataQuery = await api.get("/reports/messages", { params: { userId, startDate, endDate }, });
|
||||
|
||||
// console.log('dataQuery messages: ', dataQuery.data)
|
||||
console.log('dataQuery messages: ', dataQuery.data)
|
||||
|
||||
if (dataQuery.data.length > 0) {
|
||||
|
||||
|
@ -499,15 +500,10 @@ const Report = () => {
|
|||
}
|
||||
}
|
||||
|
||||
// console.log('dataCSVFormat: ', dataCSVFormat)
|
||||
|
||||
setDataCSV(dataCSVFormat)
|
||||
setIsMount(false);
|
||||
// setDataCSV(dataQuery.data)
|
||||
}
|
||||
|
||||
// setLoading(false);
|
||||
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
|
@ -542,16 +538,9 @@ const Report = () => {
|
|||
|
||||
socket.on("onlineStatus", (data) => {
|
||||
|
||||
// setLoading(true);
|
||||
|
||||
|
||||
let date = new Date().toLocaleDateString('pt-BR').split('/')
|
||||
let dateToday = `${date[2]}-${date[1]}-${date[0]}`
|
||||
|
||||
// console.log('date: ', new Date(startDate).toLocaleDateString('pt-BR'))
|
||||
// console.log('date2: ', startDate)
|
||||
|
||||
|
||||
if (data.action === "logout" || (data.action === "update" &&
|
||||
((`${startDate}` === `${endDate}`) && (`${endDate}` === `${dateToday}`) && (`${startDate}` === `${dateToday}`)))) {
|
||||
|
||||
|
@ -564,8 +553,6 @@ const Report = () => {
|
|||
dispatchQ({ type: "DELETE_USER_STATUS", payload: data.userOnlineTime });
|
||||
}
|
||||
|
||||
// setLoading(false);
|
||||
|
||||
});
|
||||
|
||||
socket.on("user", (data) => {
|
||||
|
@ -581,9 +568,13 @@ const Report = () => {
|
|||
};
|
||||
|
||||
}
|
||||
else if (reportOption === "1") {
|
||||
dispatchQ({ type: "RESET" })
|
||||
setTicketsPageNumber(1)
|
||||
}
|
||||
|
||||
|
||||
}, [reportOption, startDate, endDate]);
|
||||
}, [reportOption, startDate, endDate, userId]);
|
||||
|
||||
|
||||
// const handleDeleteRows = (id) => {
|
||||
|
@ -610,6 +601,7 @@ const Report = () => {
|
|||
|
||||
setData(query.map((column) => { return { ...column } }))
|
||||
|
||||
|
||||
}, [query])
|
||||
|
||||
const handleLogouOnlineUser = async (userId) => {
|
||||
|
@ -625,6 +617,30 @@ const Report = () => {
|
|||
};
|
||||
|
||||
|
||||
const loadMore = () => {
|
||||
setTicketsPageNumber((prevState) => prevState + 1);
|
||||
};
|
||||
|
||||
const handleScroll = (e) => {
|
||||
|
||||
if (!hasMore || loading) return;
|
||||
|
||||
const { scrollTop, scrollHeight, clientHeight } = e.currentTarget;
|
||||
|
||||
// console.log('scrollTop: ', scrollTop,
|
||||
// ' | scrollHeight: ', scrollHeight,
|
||||
// ' | clientHeight: ', clientHeight,
|
||||
// ' | scrollHeight - (scrollTop + 1): ', scrollHeight - (scrollTop + 1))
|
||||
|
||||
if (scrollHeight - (scrollTop + 1) < clientHeight) {
|
||||
|
||||
loadMore();
|
||||
|
||||
// e.currentTarget.scrollTo(0, 200);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
|
||||
<Can
|
||||
|
@ -639,7 +655,7 @@ const Report = () => {
|
|||
return { 'value': obj.id, 'label': obj.name }
|
||||
})} /></Item>
|
||||
|
||||
<Item><DatePicker1 func={datePicker1Value} minDate={true} startEmpty={false} title={'Data inicio'} /></Item>
|
||||
<Item><DatePicker1 func={datePicker1Value} minDate={false} startEmpty={false} title={'Data inicio'} /></Item>
|
||||
<Item><DatePicker2 func={datePicker2Value} minDate={false} startEmpty={false} title={'Data fim'} /></Item>
|
||||
|
||||
<Item sx={{ display: 'grid', gridColumn: '4 / 5', }}>
|
||||
|
@ -651,13 +667,15 @@ const Report = () => {
|
|||
{reportOption === '1' &&
|
||||
|
||||
<div>
|
||||
{/* <Button
|
||||
<Button style={{display: "none"}}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={(e) => handleCSVMessages()}
|
||||
onClick={(e) => {
|
||||
handleCSVMessages()
|
||||
}}
|
||||
>
|
||||
{"CSV ALL"}
|
||||
</Button> */}
|
||||
</Button>
|
||||
|
||||
<div>
|
||||
<CSVLink
|
||||
|
@ -674,10 +692,6 @@ const Report = () => {
|
|||
|
||||
</Item>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</Box>
|
||||
|
||||
<Box sx={{
|
||||
|
@ -688,11 +702,22 @@ const Report = () => {
|
|||
|
||||
{reportOption === '1' &&
|
||||
|
||||
// <div onScroll={handleScroll} style={{ height: 400, overflowY: "scroll" }}>
|
||||
// </div>
|
||||
|
||||
<>
|
||||
|
||||
<MTable data={query}
|
||||
columns={columnsData}
|
||||
hasChild={true}
|
||||
removeClickRow={false}
|
||||
|
||||
handleScroll={handleScroll}
|
||||
|
||||
table_title={'Atendimento por atendentes'} />
|
||||
|
||||
</>
|
||||
|
||||
}
|
||||
{reportOption === '2' &&
|
||||
|
||||
|
@ -711,7 +736,7 @@ const Report = () => {
|
|||
[
|
||||
|
||||
// { title: 'Foto', field: 'ticket.contact.profilePicUrl', render: rowData => <img src={rowData['ticket.contact.profilePicUrl']} alt="imagem de perfil do whatsapp" style={{ width: 40, borderRadius: '50%' }} /> },
|
||||
{ title: 'Nome', field: 'name', cellStyle: {whiteSpace: 'nowrap'}, },
|
||||
{ title: 'Nome', field: 'name', cellStyle: { whiteSpace: 'nowrap' }, },
|
||||
|
||||
{
|
||||
title: 'Status', field: 'statusOnline.status',
|
||||
|
|
|
@ -21,12 +21,8 @@ import { AuthProvider } from "../context/Auth/AuthContext";
|
|||
import { WhatsAppsProvider } from "../context/WhatsApp/WhatsAppsContext";
|
||||
import Route from "./Route";
|
||||
|
||||
|
||||
//console.log('---AuthProvider: ',AuthProvider)
|
||||
|
||||
|
||||
|
||||
|
||||
const Routes = () => {
|
||||
return (
|
||||
<BrowserRouter>
|
||||
|
@ -37,41 +33,18 @@ const Routes = () => {
|
|||
<WhatsAppsProvider>
|
||||
<LoggedInLayout>
|
||||
<Route exact path="/" component={Dashboard} isPrivate />
|
||||
<Route
|
||||
exact
|
||||
path="/tickets/:ticketId?"
|
||||
component={Tickets}
|
||||
isPrivate
|
||||
/>
|
||||
<Route exact path="/tickets/:ticketId?" component={Tickets} isPrivate />
|
||||
|
||||
<Route
|
||||
exact
|
||||
path="/connections"
|
||||
component={Connections}
|
||||
isPrivate
|
||||
/>
|
||||
|
||||
|
||||
<Route
|
||||
exact
|
||||
path="/report"
|
||||
component={Report}
|
||||
isPrivate
|
||||
/>
|
||||
<Route exact path="/connections" component={Connections} isPrivate />
|
||||
|
||||
<Route exact path="/report" component={Report} isPrivate />
|
||||
|
||||
<Route exact path="/contacts" component={Contacts} isPrivate />
|
||||
|
||||
<Route exact path="/schedulesReminder" component={SchedulesReminder} isPrivate />
|
||||
|
||||
|
||||
<Route exact path="/users" component={Users} isPrivate />
|
||||
<Route
|
||||
exact
|
||||
path="/quickAnswers"
|
||||
component={QuickAnswers}
|
||||
isPrivate
|
||||
/>
|
||||
<Route exact path="/quickAnswers" component={QuickAnswers} isPrivate />
|
||||
<Route exact path="/Settings" component={Settings} isPrivate />
|
||||
<Route exact path="/Queues" component={Queues} isPrivate />
|
||||
</LoggedInLayout>
|
||||
|
|
|
@ -29,6 +29,7 @@ const rules = {
|
|||
"show-icon-add-queue",
|
||||
"show-icon-edit-queue",
|
||||
"show-icon-delete-queue",
|
||||
"space-disk-info:show",
|
||||
|
||||
|
||||
"drawer-admin-items:view",
|
||||
|
|
Loading…
Reference in New Issue